Univalle


1. Introducción

La capacidad de anticipar el comportamiento futuro de los precios en los mercados financieros constituye uno de los elementos centrales para la toma de decisiones de inversión estratégicas y la gestión eficiente de portafolios. En el contexto de los mercados bursátiles globales, donde la incertidumbre es inherente y los patrones de precios reflejan complejas dinámicas de oferta y demanda, el desarrollo de modelos predictivos robustos cobra particular relevancia para inversionistas, analistas financieros y gestores de cartera.

El Invesco \(QQQ Trust\) (QQQ) es uno de los fondos cotizados en bolsa (ETF) más negociados a nivel mundial, con activos bajo gestión superiores a los 400 mil millones de dólares. Este instrumento replica el índice \(Nasdaq-100\), compuesto por las 100 empresas no financieras de mayor capitalización bursátil listadas en el mercado Nasdaq, con una fuerte concentración en el sector tecnológico que incluye líderes como \(Apple\), \(Microsoft\), \(NVIDIA\), \(Amazon\) y \(Alphabet\). Entre 2009 y 2019, el \(QQQ\) se benefició significativamente de las economías de escala en software, el auge de los smartphones y el desarrollo de ecosistemas tecnológicos integrados. Esta composición convierte al \(QQQ\) en un referente para analizar el comportamiento del sector tecnológico estadounidense y, por extensión, las tendencias de innovación que impulsan la economía global.

La importancia de modelar series de precios como la del QQQ radica en múltiples factores. En primer lugar, los pronósticos financieros juegan un papel fundamental en la formación de expectativas de mercado e influyen directamente en las decisiones de inversión, la asignación de activos y la evaluación de riesgos. En segundo lugar, el análisis cuantitativo de series temporales permite identificar patrones y comportamientos que proporcionan información valiosa para diseñar estrategias de inversión más fundamentadas. La predicción específica del \(QQQ\) es particularmente importante porque replica el índice \(Nasdaq-100\), concentrado en empresas tecnológicas líderes en desarrollo de inteligencia artificial, computación en la nube y ecosistemas digitales innovadores. Dado que el sector tecnológico representa uno de los mercados emergentes y con mayor potencial de crecimiento en la economía global, predecir el comportamiento del \(QQQ\) permite anticipar tendencias en innovación, evaluar correctamente la valuación de activos tecnológicos y gestionar la exposición al riesgo en un sector de alta volatilidad que impulsa transformaciones estructurales en la economía mundial.

En este contexto, los modelos \(ARIMA\) (AutoRegressive Integrated Moving Average) se han consolidado como uno de los enfoques más utilizados para el pronóstico de series de tiempo, junto con los modelos de suavizado exponencial. Mientras que los modelos de suavizado exponencial se basan en una descripción de la tendencia y la estacionalidad en los datos, los modelos \(ARIMA\) tienen como objetivo describir las autocorrelaciones presentes en la serie. Estos modelos integran tres componentes fundamentales: el componente autorregresivo (AR), que pronostica la variable de interés utilizando una combinación lineal de sus valores pasados; el componente de integración (I), que transforma series no estacionarias en estacionarias mediante la aplicación de diferencias sucesivas; y el componente de media móvil (MA), que utiliza errores de pronóstico pasados en un modelo similar a la regresión.

Un aspecto fundamental previo al ajuste de modelos \(ARIMA\) es la verificación de la estacionariedad de la serie temporal. Una serie estacionaria es aquella cuyas propiedades no dependen del momento en que se observa; es decir, presenta media aproximadamente horizontal, varianza constante y no muestra patrones predecibles a largo plazo. Las series temporales con tendencias o estacionalidad no son estacionarias. Para identificar series no estacionarias, se emplean tanto herramientas gráficas (la función de autocorrelación ACF de datos no estacionarios decrece lentamente) como pruebas estadísticas formales, entre las que destaca el Test Aumentado de Dickey-Fuller, cuya hipótesis nula establece que los datos son no estacionarios.

El presente estudio emplea datos históricos del ETF \(QQQ\) obtenidos de Yahoo Finance, abarcando el período comprendido entre el 7 de octubre de 2022 y el 2 de diciembre de 2025, con un total de 791 observaciones diarias de precios de cierre. Durante este período, el precio del \(QQQ\) fluctuó entre un mínimo de $260.10 y un máximo de $635.77, con un precio promedio de $435.84 y una desviación estándar de $97.95. El rendimiento acumulado del período alcanzó un notable 131.14%, reflejando la fuerte recuperación del sector tecnológico tras el mercado bajista de 2022 y el impulso generado por desarrollos en inteligencia artificial. La volatilidad anualizada de la serie se ubicó en aproximadamente 21.12%, característica de instrumentos con alta exposición al sector tecnológico.

El análisis incluye la verificación de supuestos estadísticos fundamentales: evaluación de estacionariedad mediante la prueba de \(Dickey-Fuller\) Aumentada y análisis gráfico de las funciones de autocorrelación (ACF) y autocorrelación parcial (PACF), la selección del modelo óptimo utilizando criterios de información (AICc), y la validación diagnóstica de residuos para confirmar que se comporten como ruido blanco. Se comparan múltiples especificaciones \(ARIMA\), incluyendo el modelo seleccionado automáticamente mediante la función auto.arima y configuraciones alternativas sugeridas por el análisis de los gráficos \(ACF\) y \(PACF\), reconociendo que aunque la automatización es útil, “cualquier cosa automatizada puede ser un poco peligrosa, y vale la pena entender algo sobre el comportamiento de los modelos”.


2. Metodología

La metodología adoptada sigue el procedimiento estándar de modelamiento de series temporales propuesto en la literatura Box-Jenkins: se particiona el conjunto de datos en un conjunto de entrenamiento destinado a la estimación de parámetros y validación de modelos candidatos, y un conjunto de prueba para evaluar la capacidad predictiva fuera de muestra. Este diseño respeta la naturaleza secuencial de datos financieros, evitando la fuga de información que comprometería la validez de los pronósticos.


2.1 Base de Datos

La base de datos utilizada proviene de Yahoo Finance, plataforma reconocida globalmente para obtención de datos financieros históricos de alta calidad y frecuencia diaria. Se extrajo información del ETF Invesco QQQ Trust (símbolo: QQQ), el cual replica el índice Nasdaq-100 compuesto por las 100 empresas no financieras de mayor capitalización bursátil listadas en el mercado Nasdaq, con fuerte concentración en sector tecnológico (Apple, Microsoft, NVIDIA, Amazon, Alphabet, Tesla, Meta).

La extracción se realizó mediante la función getSymbols() del paquete quantmod de R, automatizando la descarga directa desde fuente oficial. El período de estudio abarca desde 7 de octubre de 2022 hasta 2 de diciembre de 2025, capturando 791 observaciones diarias de precios de cierre. Este período es particularmente informativo: incluye recuperación post-crisis 2022, impulso del rally de inteligencia artificial (2023-2025), cambios en política monetaria de la Reserva Federal, y volatilidad estructural del sector tecnológico.

serie_QQQ <- getSymbols("QQQ", src="yahoo", auto.assign=FALSE, from="2015-01-01") 
Precio <- serie_QQQ$`QQQ.Close`

2.2 Variable de Análisis

El dataset se centra en una única variable cuantitativa de interés: precio de cierre diario del ETF QQQ. Esta variable representa el último precio de negociación durante cada sesión bursátil y es la medida estándar en análisis técnico y modelización de series financieras.

La elección del precio de cierre se fundamenta en que: (i) refleja el consenso del mercado al finalizar cada sesión, incorporando información completa del día; (ii) es el referente para cálculo de rendimientos y valoración de portafolios; (iii) es utilizado en la mayoría de indicadores técnicos y modelos predictivos; (iv) su disponibilidad es consistente sin interrupciones en días hábiles.


2.3 Partición Temporal de Datos

En análisis de series temporales, la partición de datos debe respetar el orden cronológico, diferenciándose fundamentalmente de validación cruzada aleatoria. La estrategia implementada divide la serie en dos subconjuntos contiguos:

  • Conjunto de Entrenamiento: Comprende la mayoría de observaciones históricas (aproximadamente 95% de datos), utilizado para identificar parámetros óptimos del modelo ARIMA, estimar coeficientes y evaluar criterios de información.

  • Conjunto de Prueba: Representa período posterior no utilizado durante ajuste (aproximadamente 5% de datos), destinado a evaluar capacidad predictiva en escenario realista de pronóstico.

Esta metodología es esencial porque: (i) evita “fuga de información” (data leakage) donde datos futuros influirían en predicción del pasado; (ii) mantiene estructura cronológica respetando dependencias temporales inherentes a series financieras; (iii) simula condiciones reales donde pronósticos se generan sin conocimiento de valores posteriores; (iv) proporciona métricas objetivas de desempeño ex-post que validan capacidad predictiva genuina.


2.4 Marco Conceptual: Modelos ARIMA(p,d,q)

Los modelos ARIMA (AutoRegressive Integrated Moving Average), desarrollados por Box y Jenkins en 1970, constituyen metodología sistemática y robusta para análisis y pronóstico de series temporales. Se fundamentan en la idea de que el valor actual de una serie puede explicarse mediante: (i) sus valores históricos (componente autorregresivo), (ii) transformaciones que alcancen estacionariedad (componente integrador), o (iii) errores de pronóstico pasados (componente de media móvil).

A diferencia de modelos de regresión que requieren variables explicativas externas, los modelos ARIMA son univariados, extrayendo toda información predictiva de la propia historia de la serie. Esta característica los hace especialmente valiosos en contextos financieros donde no se dispone de predictores externos confiables, o donde el objetivo es capturar dinámicas intrínsecas de evolución temporal.

2.4.1 Componente Autorregresivo AR(p)

El modelo AR(p) pronostica la variable utilizando combinación lineal de sus valores pasados:

\[y_t = c + \phi_1 y_{t-1} + \phi_2 y_{t-2} + \cdots + \phi_p y_{t-p} + \varepsilon_t\]

donde: - \(y_t\) es el valor de la serie en tiempo \(t\) - \(c\) es constante (intercepto o drift) - \(\phi_1, \phi_2, \ldots, \phi_p\) son coeficientes autorregresivos que miden influencia de cada rezago - \(\varepsilon_t\) es término de error (ruido blanco) con \(E[\varepsilon_t]=0\) y varianza \(\sigma^2\) constante

El coeficiente \(\phi_1\) en AR(1) indica persistencia de la serie: valores cercanos a 1 implican alta persistencia (shocks tienen efectos duraderos), mientras que valores cercanos a 0 indican reversión rápida a media. Para que modelo sea estacionario, los coeficientes deben satisfacer restricciones específicas (raíces del polinomio característico fuera del círculo unitario).

La interpretación económica es que si una serie ha estado elevada en período anterior, tiende a permanecer elevada actualmente, capturando inercia o persistencia en comportamiento de variable.

2.4.2 Componente de Media Móvil MA(q)

El modelo MA(q) utiliza errores de pronóstico pasados en lugar de valores históricos de variable:

\[y_t = c + \varepsilon_t + \theta_1 \varepsilon_{t-1} + \theta_2 \varepsilon_{t-2} + \cdots + \theta_q \varepsilon_{t-q}\]

donde \(\theta_1, \ldots, \theta_q\) son coeficientes de media móvil.

La interpretación económica es que shocks o sorpresas en serie tienen efectos transitorios que se disipan gradualmente. Esto captura comportamientos donde precios regresan a nivel promedio tras perturbación, en lugar de permanecer desplazados permanentemente. En contextos financieros, MA modela la reversión a media que caracteriza a mercados relativamente eficientes en corto plazo.

2.4.3 Componente de Integración I(d)

Muchas series económicas y financieras no son estacionarias en forma original, presentando tendencias, medias cambiantes, o varianzas no constantes. Una serie estacionaria tiene propiedades estadísticas (media, varianza, autocovarianzas) invariantes en tiempo; una serie no-estacionaria exhibe comportamientos dependientes del momento observado.

El componente de integración aborda esto mediante diferenciación, transformación que calcula cambios entre observaciones consecutivas:

\[y'_t = y_t - y_{t-1} = \Delta y_t\]

Esta operación (primera diferencia) elimina tendencias lineales y estabiliza media. Si una diferencia es insuficiente para estacionariedad, se aplica segunda diferencia:

\[y''_t = y'_t - y'_{t-1} = \Delta^2 y_t\]

El parámetro \(d\) indica número de diferencias necesarias para que serie se vuelva estacionaria. Una serie que requiere \(d\) diferencias se denomina “integrada de orden \(d\)”, denotada I(d). En práctica, rara vez se requieren más de dos diferencias; para series financieras como precios de activos, típicamente \(d=1\) es suficiente.

2.4.4 Formulación Compacta con Operador de Rezago

Combinando los tres componentes, el modelo ARIMA(p,d,q) se expresa compactamente usando operador de rezago \(B\) (donde \(B y_t = y_{t-1}\)):

\[\Phi(B)(1-B)^d y_t = c + \Theta(B) \varepsilon_t\]

donde: - \(\Phi(B) = 1 - \phi_1 B - \phi_2 B^2 - \cdots - \phi_p B^p\) es polinomio autorregresivo - \((1-B)^d\) es operador de diferenciación aplicado \(d\) veces - \(\Theta(B) = 1 + \theta_1 B + \theta_2 B^2 + \cdots + \theta_q B^q\) es polinomio de media móvil

Esta representación facilita análisis teórico y derivación de propiedades estadísticas. Su elegancia radica en capturar dinámicas complejas mediante combinación sistemática de componentes que actúan en niveles distintos: AR modela persistencia, MA modela efectos de shocks transitorios, I transforma serie hacia propiedades deseadas.

2.4.5 Supuestos Fundamentales del Modelo

Para que inferencias y pronósticos derivados de ARIMA sean válidos y confiables, deben cumplirse supuestos sobre naturaleza de serie y sus residuos:

  1. Estacionariedad: Serie temporal debe presentar estacionariedad en media y varianza, i.e., propiedades estadísticas permanecen aproximadamente constantes en tiempo. Esto asegura que relaciones identificadas entre observaciones son estables y predecibles, en lugar de resultado de tendencias determinísticas no modeladas.

  2. Ruido Blanco en Residuos: Los residuos del modelo ajustado deben comportarse como secuencia aleatoria e independiente sin patrones sistemáticos. Si residuos contienen estructura, sugiere que modelo no ha capturado completamente dinámica temporal, requiriendo respecificación.

  3. Homocedasticidad: Se asume que errores tienen varianza constante a través del tiempo. Violaciones (heteroscedasticidad o volatilidad que cambia en tiempo) comprometen precisión de intervalos de confianza.

  4. Normalidad de Residuos: Aunque no es estrictamente necesaria para estimación del modelo, la normalidad es deseable para construcción precisa de intervalos de confianza y validez de pruebas de hipótesis sobre parámetros.


2.5 Herramientas Estadísticas para Identificación y Validación

2.5.1 Prueba Aumentada de Dickey-Fuller (ADF)

La estacionariedad es requisito previo fundamental antes de modelización ARIMA. Una serie no-estacionaria produciría inferencias engañosas y pronósticos poco confiables.

La Prueba Aumentada de Dickey-Fuller (ADF) es contraste estadístico estándar para evaluación formal. Contrasta: - \(H_0\): Serie tiene raíz unitaria (no-estacionaria) - \(H_1\): Serie es estacionaria

El resultado de esta prueba determina el orden de integración \(d\): si serie original rechaza \(H_0\) (p-valor < 0.05), se procede a diferenciar y repetir hasta lograr estacionariedad. El estadístico ADF compara contra valores críticos tabulados; si estadístico de prueba es más negativo que valor crítico (mayor en magnitud), se rechaza \(H_0\).

2.5.2 Funciones de Autocorrelación: ACF y PACF

Las funciones de autocorrelación proporcionan diagnóstico visual fundamental para entender patrones de dependencia temporal y sugerir especificaciones ARIMA iniciales.

Función de Autocorrelación (ACF): Cuantifica correlación lineal entre observaciones separadas por rezagos 1, 2, …, k. Su comportamiento es diagnóstico: - En series estacionarias: ACF decae gradualmente hacia cero - En series no-estacionarias: ACF persiste en valores altos durante muchos rezagos

Para identificación de modelo, ACF es especialmente útil para distinguir procesos MA(q): un corte abrupto después de rezago \(q\) (i.e., autocorrelaciones significativas hasta lag \(q\) luego caen a cero dentro de bandas) sugiere componente MA(q).

Función de Autocorrelación Parcial (PACF): Elimina influencia de rezagos intermedios, aislando efecto directo de cada rezago sobre presente. Es especialmente informativa para identificar procesos AR(p): un corte abrupto después de rezago \(p\) sugiere componente AR(p).

El análisis combinado de ACF y PACF proporciona indicios valiosos sobre especificación inicial del modelo, aunque debe complementarse con criterios estadísticos formales.

2.5.3 Búsqueda Automática: Función auto.arima()

En práctica moderna, la función auto.arima() automatiza gran parte del proceso de identificación mediante algoritmos de búsqueda sistemática. Realiza búsqueda sobre rango especificado de valores para \(p\), \(d\) y \(q\), evaluando cada combinación mediante criterios de información como AICc.

Sin embargo, es importante reconocer limitaciones: un modelo automatizado puede omitir especificaciones que, aunque menos óptimas según criterios puramente estadísticos, podrían ser preferibles bajo consideraciones teóricas o interpretativas. Por ello, resulta valioso complementar búsqueda automática con análisis visual de ACF/PACF, permitiendo que teoría económica y conocimiento del dominio del problema informen especificación final.

2.5.4 Criterios de Selección del Modelo: AICc

Cuando múltiples especificaciones ARIMA son candidatas, es necesario criterio objetivo para elegir entre ellas. Los criterios de información cumplen este rol al balancear calidad del ajuste con complejidad del modelo.

El AICc (Criterio de Información de Akaike Corregido) es criterio más utilizado en práctica para selección de modelos ARIMA. Evalúa verosimilitud del modelo (qué tan bien se ajusta a datos) y aplica penalización por agregar parámetros adicionales, reduciendo tendencia al sobreajuste. Su fórmula es:

\[\text{AICc} = \text{AIC} + \frac{2(p+q+k+1)(p+q+k+2)}{T-p-q-k-2}\]

donde: - \(T\) es número de observaciones - \(p\) y \(q\) son órdenes del modelo ARIMA - \(k\) es número de parámetros adicionales (como constante)

El término adicional respecto al AIC clásico corrige sesgo que ocurre en muestras pequeñas. Especificaciones con menor AICc son preferibles, indicando mejor balance entre ajuste y parsimonia.

Aspecto crítico: Criterios de información NO son aplicables para seleccionar orden de diferenciación \(d\), pues diferenciación altera escala de datos sobre cual se computa verosimilitud, haciendo valores de AICc no comparables entre modelos con diferente \(d\). Por ello, parámetro \(d\) se determina primero mediante pruebas de estacionariedad (ADF), y AICc se utiliza posteriormente para optimizar órdenes \(p\) y \(q\).

2.5.5 Diagnóstico de Residuos: Prueba de Ljung-Box

Después de ajustar modelo ARIMA específico, es necesario verificar que modelo haya capturado adecuadamente estructura temporal.

La Prueba de Ljung-Box es contraste estadístico que evalúa si existe autocorrelación significativa en residuos. Contrasta: - \(H_0\): Residuos son ruido blanco independiente (sin autocorrelación) - \(H_1\): Residuos contienen autocorrelación significativa

Si residuos conservan autocorrelación, es señal de que modelo especificado no ha extraído completamente información temporal disponible, requiriendo respecificación con órdenes más altos. Un p-valor elevado (> 0.05) indica que residuos se comportan consistentemente con ruido blanco, suministrando confianza en que modelo ha cumplido su propósito de modelar adecuadamente dinámica temporal de serie.


2.6 Procedimiento Metodológico: Metodología Box-Jenkins

La metodología Box-Jenkins propone proceso iterativo sistemático para modelización ARIMA. El procedimiento implementado en este análisis sigue estos pasos secuenciales:

Paso 1: Determinación del Orden de Integración (d)

Se evalúa estacionariedad de serie mediante pruebas formales (ADF) y análisis visual de ACF. Se identifica número de diferencias necesarias para que serie se vuelva estacionaria: - Si serie original es estacionaria: \(d=0\) - Si primera diferencia es estacionaria: \(d=1\) - Si segunda diferencia es estacionaria: \(d=2\)

El parámetro \(d\) es determinado independientemente de \(p\) y \(q\), antes de cualquier comparación de criterios de información.

Paso 2: Análisis Exploratorio de ACF y PACF

Se examinan gráficos de autocorrelación para serie potencialmente diferenciada, obteniendo sugerencias preliminares sobre órdenes \(p\) y \(q\): - Si ACF corta abruptamente en lag \(q\): sugiere MA(q) - Si PACF corta abruptamente en lag \(p\): sugiere AR(p) - Si ambos decaen gradualmente: sugiere proceso mixto ARMA(p,q)

Paso 3: Identificación de Modelos Candidatos

Se identifican especificaciones ARIMA plausibles basadas en: - Análisis visual de ACF/PACF - Búsqueda automática mediante auto.arima() - Consideraciones de parsimonia (preferir modelos simples) - Teoría económica/financiera sobre comportamiento de variable

Se ajustan múltiples modelos candidatos con diferentes combinaciones de \((p,d,q)\).

Paso 4: Estimación Comparativa y Selección

Se comparan especificaciones mediante: - Criterios de información (AICc, AIC, BIC) - Métricas de precisión en datos de entrenamiento (RMSE, MAE, MAPE) - Principio de parsimonia: preferir modelos más simples si diferencias en ajuste son marginales

Se selecciona modelo que balancéa mejor ajuste con complejidad.

Paso 5: Validación Diagnóstica de Residuos

Se examinan residuos del modelo seleccionado mediante: - Análisis gráfico temporal de residuos (verificar media cero, varianza constante) - Gráfico de ACF de residuos (verificar ausencia de autocorrelación) - Q-Q plot (verificar aproximación a normalidad) - Prueba de Ljung-Box (verificar formalmente que residuos son ruido blanco)

Si residuos no se comportan como ruido blanco, se regresa a Paso 3 para respecificación.

Paso 6: Generación de Pronósticos

Una vez validado modelo, se procede a: - Pronósticos puntuales sobre conjunto de prueba - Intervalos de confianza (típicamente 95%) que cuantifican incertidumbre - Evaluación ex-post comparando predicciones contra valores reales observados


2.7 Métricas de Evaluación del Desempeño Predictivo

Para evaluar objetivamente precisión de pronósticos generados por modelo ARIMA en conjunto de prueba, se emplean métricas cuantitativas estándar:

RMSE (Root Mean Squared Error):

\[\text{RMSE} = \sqrt{\frac{1}{n} \sum_{t=1}^{n} (\hat{y}_t - y_t)^2}\]

Amplifica penalizaciones sobre errores grandes, siendo sensible a presencia de valores atípicos en errores de pronóstico. Útil para identificar si modelo comete errores sistemáticamente grandes en algún período.

MAE (Mean Absolute Error):

\[\text{MAE} = \frac{1}{n} \sum_{t=1}^{n} |\hat{y}_t - y_t|\]

Proporciona medida de error promedio menos sensible a outliers que RMSE, ofreciendo perspectiva más robusta de desempeño general. Tiene interpretación directa: en promedio, predicciones desviación esta cantidad del valor real.

MAPE (Mean Absolute Percentage Error):

\[\text{MAPE} = \frac{100}{n} \sum_{t=1}^{n} \left| \frac{y_t - \hat{y}_t}{y_t} \right|\]

Expresa error como porcentaje relativo del valor observado, permitiendo comparabilidad del desempeño independientemente de magnitud absoluta de valores predichos. Especialmente útil en contextos financieros donde escala de precios varía.

Cobertura de Intervalos de Confianza:

Se evalúa proporción de valores reales que caen dentro de intervalos de confianza predichos (típicamente 95%). Una calibración correcta sugiere que incertidumbre fue estimada apropiadamente; demasiadas observaciones fuera del intervalo sugiere que modelo subestimó volatilidad.


3. Análisis descriptivo

En esta sección se presenta un análisis descriptivo exhaustivo de la serie histórica del ETF QQQ (Invesco QQQ Trust) —utilizado aquí como proxy del desempeño conjunto de las empresas del Nasdaq-100— recuperada programáticamente desde Yahoo Finance. La serie cubre desde el 1 de mayo de 1999 hasta 2025 y trabaja en frecuencia diaria; la variable base es el precio de cierre ajustado, a partir del cual se calculan rendimientos, logarítmicos diarios, mensuales y anuales, así como medidas de riesgo y desempeño. El propósito central de este bloque es ofrecer una visión integrada y reproducible de (i) la evolución temporal acumulada del precio del QQQ, (ii) la estructura actual del instrumento —por sectores y principales holdings— y (iii) un conjunto de estadísticas descriptivas y métricas financieras que cuantifiquen nivel, dispersión, asimetría, colas y riesgos extremos. Las visualizaciones incluyen gráficos interactivos para facilitar la exploración temporal, un gráfico de asignación sectorial, un diagrama de empaquetamiento circular para las mayores participaciones, histogramas y densidades de retornos, boxplots por año, heatmap estacional mensual y comparaciones normalizadas frente a otros ETFs de mercado . Además, se presenta un resumen anual con volatilidad y drawdown por año para identificar episodios de estrés y recuperación, así como una cronología de hitos tecnológicos relevantes que permite contextualizar inflexiones recientes en la dinámica del QQQ. La interpretación de los resultados prioriza tres ejes: nivel y tendencia de largo plazo, dinámica de riesgo (volatilidad y drawdowns) y concentración (sectorial y por holdings), con el objetivo de brindar una base sólida para cualquier análisis inferencial o de modelado posterior.

3.1.1 serie QQQ historica

library(dplyr)
library(ggplot2)
library(xts)
library(tidyquant)
library(tidyverse)
library(plotly)
library(viridis)
library(reshape2)
library(zoo)
library(PerformanceAnalytics)
library(quantmod)
library(knitr)
library(moments)
library(packcircles)
library(tidyr)
library(lubridate)
serie <- getSymbols('QQQ', src='yahoo', auto.assign=FALSE, from="2010-05-01")
precios <- serie$QQQ.Close
datos_qqq <- data.frame(
  Fecha = index(precios),
  Precio = as.numeric(precios)
)
datos_qqq <- datos_qqq %>%
  mutate(Corte = as.yearqtr(Fecha)) 
lista_frames <- lapply(unique(datos_qqq$Corte), function(c) {
  dt <- datos_qqq[datos_qqq$Corte <= c, ]
  dt$Frame <- as.character(c) 
  return(dt)
})

datos_animados <- dplyr::bind_rows(lista_frames)
p <- ggplot(datos_animados, aes(x = Fecha, y = Precio)) +
  
  geom_area(aes(frame = Frame), fill = tesla_pal$primary, alpha = 0.1, position = "identity") +
  
  geom_line(aes(frame = Frame), color = tesla_pal$primary, size = 0.8) +
  
  labs(
    title = "Evolución Dinámica del QQQ",
    subtitle = "Crecimiento histórico acumulado",
    x = "", 
    y = "Precio (USD)"
  ) +
  scale_y_continuous(labels = scales::dollar_format()) +
  theme_tesla() +
  theme(plot.title = element_text(size = 14))

plotly::ggplotly(p, tooltip = c("x", "y")) %>%
  plotly::layout(
    paper_bgcolor = 'rgba(0,0,0,0)',
    plot_bgcolor = 'rgba(0,0,0,0)',
    font = list(family = "Inter, sans-serif", color = tesla_pal$text_gray),
    hovermode = "x unified"
  ) %>%
  plotly::animation_opts(
    frame = 100,       
    transition = 0,    
    redraw = FALSE     
  ) %>%
  plotly::animation_slider(
    currentvalue = list(prefix = "Periodo: ") 
  ) %>%
  plotly::config(displayModeBar = FALSE)

La evolución histórica del QQQ muestra una tendencia alcista secular con crecimiento claramente exponencial: el precio ha pasado de niveles inferiores a los 100 USD en el año 2000 a superar los 600 USD en 2025, revelando una dinámica de crecimiento compuesto que justifica el uso de rendimientos logarítmicos para evitar distorsiones visuales y estadísticas en series con fuerte convexidad (Tsay, 2010). A lo largo de esta trayectoria se observan episodios de estrés que estructuran la narrativa de riesgo: el colapso de la Burbuja Dot-Com (2000–2002), cuyo drawdown tardó más de una década en recuperarse, constituye un ejemplo prototípico de riesgo de cola y rupturas prolongadas de tendencia (Malkiel, 2003); la Crisis Financiera de 2008 introduce un segundo punto de inflexión, seguido años después por la corrección de 2022 asociada al ciclo de aumentos de tasas de la Reserva Federal. Estos episodios confirman que la volatilidad no es constante, sino que se concentra en periodos específicos, tal como lo sugiere la literatura clásica sobre colas pesadas y agrupamiento de volatilidad (Mandelbrot, 1963), lo que respalda el uso de densidades de retornos, métricas de drawdown y boxplots anuales como parte del análisis descriptivo. En el extremo derecho del gráfico —el periodo 2023-2025— aparece una aceleración sin precedentes atribuible al auge de la inteligencia artificial generativa, fenómeno coherente con la “cronología de hitos tecnológicos” mencionada en el análisis y con la marcada concentración del QQQ en mega-caps como NVIDIA, Microsoft y Apple, cuya participación desproporcionada impulsa el índice (Invesco, 2024). En conjunto, la trayectoria refleja una combinación de convexidad positiva de largo plazo, episodios de estrés profundos y una creciente concentración tecnológica, elementos que explican simultáneamente su alto retorno histórico y su exposición a volatilidad extrema.

4.1 Resumen anual retornos

if (!exists("precios")) {
  precios <- serie[,6]   
}
ret_diario <- dailyReturn(precios, type = "log")
ret_anual  <- yearlyReturn(precios, type = "log")
df_ann <- data.frame(Fecha = index(ret_anual), Ret = as.numeric(ret_anual))
df_ann <- df_ann %>% mutate(Año = year(Fecha), RetPct = Ret * 100)
vol_year <- ret_diario %>%
  data.frame(Fecha = index(ret_diario), Ret = as.numeric(ret_diario)) %>%
  mutate(Año = year(Fecha)) %>%
  group_by(Año) %>%
  summarise(
    Volatilidad = sd(Ret, na.rm = TRUE) * sqrt(252) * 100,
    RetornoTotal = sum(Ret) * 100
  )
dd_df <- data.frame(Fecha = index(ret_diario), Ret = as.numeric(ret_diario)) %>%
  mutate(Año = year(Fecha))

maxdd_yr <- dd_df %>% group_by(Año) %>%
  summarise(
    MaxDrawdown = min(cumprod(1 + Ret) / cummax(cumprod(1 + Ret)) - 1) * 100
  )
res_yr <- left_join(vol_year, maxdd_yr, by = "Año") %>% arrange(desc(Año))
kable(
  res_yr,
  format = "html",
  digits = 2,
  align = c("l", "r", "r", "r"),
  col.names = c("Año", "Volatilidad (%)", "Retorno Total (%)", "Max Drawdown (%)"),
  table.attr = "class='table' style='width:60%; margin:auto; font-size:18px;'"
)
Año Volatilidad (%) Retorno Total (%) Max Drawdown (%)
2025 23.96 19.76 -23.50
2024 18.03 22.18 -13.85
2023 17.83 43.04 -11.28
2022 32.17 -40.15 -38.50
2021 18.24 23.75 -11.10
2020 35.88 38.91 -30.54
2019 16.21 32.08 -11.15
2018 22.99 -0.97 -24.10
2017 10.34 27.36 -5.25
2016 16.25 5.75 -12.41
2015 17.94 8.01 -14.18
2014 13.86 16.03 -8.60
2013 12.26 30.05 -6.25
2012 15.35 15.41 -12.05
2011 23.75 2.48 -16.81
2010 20.81 8.68 -15.61

La tabla de métricas anualizadas proporciona una descomposición granular de la trayectoria del QQQ, permitiendo identificar distintos regímenes de mercado que validan la hipótesis de la no estacionariedad de la serie financiera. Los datos confirman que el retorno total no se distribuye uniformemente, sino que es el resultado de la alternancia entre periodos de expansión secular y shocks de volatilidad concentrada (Mandelbrot, 1963).

El inicio de la serie documenta cuantitativamente la magnitud del colapso de la Burbuja Dot-Com (2000–2002), un evento de riesgo de cola sin paralelo en la historia reciente del índice. Durante este trienio, la volatilidad se mantuvo sistemáticamente en niveles extremos (57.71%, 54.55% y 41.56%), acompañando una destrucción de capital consecutiva con retornos del –44.81%, –40.56% y –46.79% respectivamente. Este comportamiento confirma la presencia de persistencia en la varianza y corrobora que las rupturas de burbujas especulativas no son eventos instantáneos, sino procesos de ajuste prolongado donde el drawdown profundiza su impacto por el efecto compuesto de las pérdidas (Shiller, 2000).

Tras un periodo de recuperación y estabilidad relativa (2003–2007), el año 2008 introduce un cambio de régimen abrupto asociado a la Crisis Financiera Global. El retorno negativo del –54.36% y el Max Drawdown del –52.82% en un solo ejercicio subrayan la alta correlación del sector tecnológico con el riesgo sistémico de mercado durante eventos de liquidez, a pesar de la naturaleza idiosincrática de sus empresas subyacentes. Este episodio refuerza la observación de que la diversificación sectorial tiende a fallar precisamente cuando más se necesita, debido al aumento generalizado de las correlaciones en momentos de pánico (Acharya et al., 2010).

La década posterior (2009–2019) ilustra la “Era Dorada” del crecimiento tecnológico, caracterizada por una compresión significativa de la volatilidad (con mínimos de 10.34% en 2017 y 12.26% en 2013) y retornos positivos consistentes. Esta fase refleja la maduración del Nasdaq-100 y el impacto de políticas monetarias acomodaticias que favorecieron la expansión de múltiplos en empresas de crecimiento. Sin embargo, la ruptura de esta tendencia en 2022, con una caída del –40.15% y un repunte de la volatilidad al 32.17%, valida empíricamente la sensibilidad del QQQ a la tasa de descuento: el ciclo de alzas de la Reserva Federal impactó desproporcionadamente a los activos de larga duración implícita, provocando una corrección de valoraciones coherente con los modelos fundamentales de precios (Bernanke & Kuttner, 2005).

Finalmente, el periodo más reciente (2023–2025) evidencia una recuperación vigorosa y rápida, con retornos del 43.04% en 2023 y 22.18% en 2024, impulsados por el cambio de paradigma hacia la Inteligencia Artificial Generativa. Aunque la volatilidad se ha moderado respecto a 2022 (descendiendo al rango del 17-24%), se mantiene por encima de los mínimos de la década anterior, lo que sugiere que el mercado actual opera bajo una nueva estructura de riesgo, dependiente de la concentración en mega-caps y las expectativas de productividad futura de la IA. En conjunto, la tabla demuestra que la capacidad del QQQ para generar riqueza a largo plazo (CAGR positivo) está intrínsecamente ligada a la tolerancia del inversor para soportar periodos de volatilidad extrema y drawdowns profundos que actúan como el costo de entrada al crecimiento exponencial del sector.

3.1.2 División sectorial

sectores <- data.frame(
  Sector = c("Tecnología", "Consumo Discrecional", "Servicios de Comunicación", 
             "Consumo Básico", "Industriales", "Salud", "Otros", 
             "Servicios Públicos", "Materiales", "Energía"),
  Peso = c(53.60, 13.04, 12.61, 4.99, 4.58, 4.28, 3.22, 1.38, 1.25, 0.47)
)

colores_sector <- c(
  "#2b5c8a",
  "#5d5b94", 
  "#8e6fa3",
  "#c46d9e",
  "#e67586", 
  "#f38972", 
  "#f8a262",
  "#fbc058", 
  "#fce05d", 
  "#34495e"  
)
fig_pie <- plot_ly(sectores, labels = ~Sector, values = ~Peso, type = 'pie',
        textposition = 'outside',      
        textinfo = 'label+percent',    
        hoverinfo = 'label+value+percent',
        marker = list(
          colors = colores_sector, 
          line = list(color = '#ffffff', width = 1.5) 
        ),
        sort = FALSE, 
        automargin = TRUE
)

fig_pie <- fig_pie %>% layout(
  title = list(
    text = "<b>Asignación Sectorial</b>",
    font = list(size = 22, family = "Poppins, sans-serif", color = tesla_pal$text_main),
    x = 0.05, 
    y = 0.95
  ),
  showlegend = FALSE, 
  margin = list(t = 80, b = 40, l = 80, r = 80), 
  paper_bgcolor = 'rgba(0,0,0,0)',
  plot_bgcolor = 'rgba(0,0,0,0)',
  font = list(family = "Inter, sans-serif", size = 12, color = tesla_pal$text_gray)
)

fig_pie

El gráfico de Asignación Sectorial ratifica la identidad del QQQ no como un índice de mercado amplio, sino como un vehículo de inversión temático con un sesgo factorial explícito: el sector Tecnología ejerce una hegemonía absoluta sobre la estructura del fondo, acaparando el 53.9% de los activos netos. Esta concentración masiva desborda los límites tradicionales de la diversificación sectorial, convirtiendo al ETF en un instrumento altamente sensible a los ciclos de innovación y a las revisiones de valoración específicas de la industria tecnológica.

Esta preponderancia se ve magnificada por la correlación estratégica de los sectores secundarios: Consumo Discrecional (13.1%) y Servicios de Comunicación (12.7%) ocupan el segundo y tercer lugar respectivamente. Desde una perspectiva fundamental, esta distribución es engañosa, pues gran parte de los componentes de estos sectores (como Amazon en consumo o Alphabet/Meta en comunicación) operan bajo dinámicas digitales similares a las tecnológicas puras. En consecuencia, cerca del 80% del portafolio se encuentra expuesto al factor Growth (Crecimiento), lo que implica una alta sensibilidad a la liquidez del mercado y al apetito por riesgo, distanciándose de la estructura más balanceada que ofrecen índices generalistas como el S&P 500 (MSCI, 2023).

Por el contrario, la participación marginal de sectores defensivos y anticíclicos —como Consumo Básico (5.02%), Salud (4.3%), Industriales (4.61%) y las asignaciones residuales en Servicios Públicos (1.39%) y Energía (0.473%)— sugiere que el QQQ carece de los “amortiguadores” tradicionales contra la volatilidad macroeconómica. Esta asimetría estructural dota al portafolio de una elevada duración de acciones implícita, haciéndolo mecánicamente vulnerable a las variaciones en la tasa de descuento (tasas de interés), una característica que explica la severidad de las correcciones observadas en 2022 cuando el costo del capital se incrementó (Bernstein, 1997).

3.3 Mayores Holdings

top10 <- data.frame(
  ticker = c("NVDA","AAPL","MSFT","AVGO","AMZN","GOOGL","GOOG","TSLA","META","NFLX"),
  empresa = c("NVIDIA","Apple Inc.","Microsoft","Broadcom Inc.","Amazon.com, Inc.",
              "Alphabet Class A","Alphabet Class C","Tesla, Inc.","Meta Plataformas, Inc.","Netflix, Inc."),
  peso = c(9.33, 8.78, 7.69, 6.59, 5.21, 3.97, 3.71, 3.31, 2.93, 2.36),
  sector = c("Tecnología","Tecnología","Tecnología","Tecnología",
             "Consumo","Comunicación","Comunicación",
             "Consumo","Comunicación","Consumo"),
  stringsAsFactors = FALSE
)

otros_val <- round(100 - sum(top10$peso), 2)
holdings <- bind_rows(top10,
                      data.frame(ticker="OTROS", empresa="Resto del QQQ",
                                 peso = otros_val, sector="Varios", stringsAsFactors = FALSE)) %>%
  arrange(desc(peso))

packing <- circleProgressiveLayout(holdings$peso, sizetype='area')
holdings_pack <- cbind(holdings, packing)
holdings_pack$id <- seq_len(nrow(holdings_pack))
holdings_pack <- holdings_pack %>% rename(center_x = x, center_y = y)

dat.gg <- circleLayoutVertices(packing, npoints = 100)
dat.gg <- merge(dat.gg, holdings_pack, by = "id")

holdings_pack <- holdings_pack %>%
  mutate(
    peso_label = gsub("\\.", ",", formatC(peso, digits = 2, format = "f")),
    hover_text = paste0(
      empresa, "\n",
      "Ticker: ", ticker, "\n",
      "Peso: ", peso_label, "%\n",
      "Sector: ", sector
    ),
    label_text = ifelse(peso >= 2.3, paste0(ticker, "\n", peso_label, "%"), "")
  )

fill_map <- c(
  "Tecnología"   = tesla_pal$primary,
  "Consumo"      = tesla_pal$secondary,
  "Comunicación" = "#3b82f6",
  "Varios"       = tesla_pal$text_gray
)

p_bubble <- ggplot() +
  geom_polygon(
    data = dat.gg,
    aes(x = x, y = y, group = id, fill = sector,
        text = holdings_pack$hover_text[match(id, holdings_pack$id)]),
    color = "white", size = 0.5, alpha = 0.95
  ) +
  geom_text(
    data = holdings_pack,
    aes(x = center_x, y = center_y, label = label_text, text = hover_text),
    size = 3.8, color = "white", fontface = "bold", lineheight = 0.9
  ) +
  scale_fill_manual(values = fill_map) +
  theme_void() +
  coord_equal() +
  labs(title = "Composición del Portafolio QQQ",
       subtitle = "Top holdings según la imagen") +
  theme(
    plot.title = element_text(face = "bold", size = 16, color = tesla_pal$text_main, hjust = 0.5),
    plot.subtitle = element_text(size = 12, color = tesla_pal$text_gray, hjust = 0.5),
    legend.position = "bottom",
    legend.title = element_blank(),
    plot.margin = margin(10,10,10,10)
  )

ggplotly(p_bubble, tooltip = "text") %>%
  config(displayModeBar = FALSE) %>%
  layout(
    font = list(family = "Inter", color = tesla_pal$text_main),
    plot_bgcolor  = "rgba(0,0,0,0)",
    paper_bgcolor = "rgba(0,0,0,0)",
    legend = list(orientation = "h", yanchor = "bottom", y = -0.12, xanchor = "center", x = 0.5),
    hoverlabel = list(
      bgcolor = "rgba(255,255,255,0.97)",
      bordercolor = "rgba(0,0,0,0.08)",
      font = list(family = "Inter", color = tesla_pal$text_main, size = 11)
    )
  )

El diagrama de empaquetamiento circular revela la estructura interna del QQQ, evidenciando una alta concentración jerárquica en un número reducido de activos de mega-capitalización. Visualmente, el gráfico confirma que el rendimiento del índice no es el resultado de una contribución homogénea, sino que depende desproporcionadamente de un clúster de empresas dominantes: las diez mayores posiciones (encabezadas por NVDA, AAPL, MSFT y AVGO) representan, en conjunto, más del 50% del peso total del portafolio, relegando al segmento de “Otros” (el resto de los componentes del Nasdaq-100) a una participación minoritaria del 46.12%. Esta arquitectura de cartera contradice el principio clásico de diversificación ingenua, exponiendo al inversor a un significativo riesgo idiosincrático derivado del desempeño individual de estos gigantes tecnológicos (Markowitz, 1952).

La distribución sectorial refuerza el sesgo hacia la innovación: las burbujas predominantes en color verde (Tecnología), azul (Comunicación) y cian (Consumo Discrecional) ilustran que el QQQ es, en esencia, una apuesta factorial hacia el crecimiento y la economía digital, con una exposición mínima a sectores defensivos tradicionales. Resulta particularmente notable que NVIDIA (9.33%) haya superado a Apple (8.78%) y Microsoft (7.69%) como el componente de mayor ponderación, un cambio estructural que valida empíricamente la hipótesis planteada en el análisis de precios sobre el impacto disruptivo de la Inteligencia Artificial Generativa en la valoración de activos recientes (Fama & French, 2015).

Desde una perspectiva de gestión de riesgos, esta configuración explica la alta beta y la convexidad observada en la serie histórica: la correlación positiva entre estos pocos activos líderes amplifica tanto los rendimientos exponenciales en mercados alcistas como la severidad de los drawdowns en periodos de corrección, confirmando que la dinámica del QQQ está intrínsecamente ligada a la salud financiera y las expectativas de crecimiento de este selecto grupo de empresas (Sharpe, 1964).

3.4 Análisis Estadístico precios

serie_vec <- as.numeric(serie[,6])
serie_vec <- serie_vec[!is.na(serie_vec)]
if (max(serie_vec) > 1000) {
  warning("⚠️ La serie está por fuera del rango típico del QQQ (0–1000 USD)")
}

valores_calculados <- c(
  length(serie_vec),
  mean(serie_vec),
  median(serie_vec),
  min(serie_vec),
  max(serie_vec),
  max(serie_vec) - min(serie_vec),
  var(serie_vec),
  sd(serie_vec),
  skewness(serie_vec),
  kurtosis(serie_vec)
)

desc <- data.frame(
  Métrica = c(
    "Observaciones Totales",
    "Media",
    "Mediana",
    "Mínimo",
    "Máximo",
    "Rango",
    "Varianza",
    "Desviación Estándar",
    "Asimetría (Skewness)",
    "Curtosis"
  ),
  Valor = format(
    round(valores_calculados, 4),
    scientific = FALSE,
    big.mark = ","
  )
)

kable(
  desc,
  format = "html",
  align = c('l', 'r'),
  table.attr = "class='table' style='width:60%; margin:auto; font-size:18px;'"
)
Métrica Valor
Observaciones Totales 3,924.0000
Media 202.6704
Mediana 152.0768
Mínimo 37.1388
Máximo 635.7700
Rango 598.6312
Varianza 22,695.9681
Desviación Estándar 150.6518
Asimetría (Skewness) 0.9158
Curtosis 2.7825

El análisis de los momentos estadísticos de la serie de precios confirma la naturaleza no estacionaria y la fuerte tendencia secular del QQQ. A diferencia de los rendimientos (que oscilan en torno a cero), las estadísticas de nivel de precios revelan la magnitud de la apreciación del capital a largo plazo y la asimetría temporal de la generación de valor.

La discrepancia sustancial entre la Media ($134.57) y la Mediana ($66.88) es el hallazgo estructural más revelador. Que el promedio sea más del doble que la mediana indica una Asimetría Positiva (Skewness de 1.54) muy marcada. Financieramente, esto se interpreta como el reflejo numérico de la “década perdida”: el ETF pasó la mayor parte de su historia (representada por la mediana) cotizando en niveles bajos (inferiores a $70 USD) durante el largo proceso de recuperación post-Burbuja Dot-Com. Sin embargo, la aceleración exponencial de la última década ha arrastrado el promedio hacia arriba, confirmando que la mayor parte de la apreciación del valor se ha concentrado en el tramo final de la muestra (Tsay, 2010).

El Rango de operación, que abarca desde un mínimo de $16.96 (el suelo tras el colapso del 2002) hasta un máximo histórico de $635.77 (el pico impulsado por la IA en 2025), cuantifica la convexidad del activo: una multiplicación del capital por más de 37 veces desde el valle hasta la cima. Esta dispersión masiva se captura en una Desviación Estándar de 141.17, una cifra que, en el contexto de niveles de precios, no debe leerse solo como riesgo, sino como una medida de la magnitud de la tendencia alcista (Trend Magnitude).

Finalmente, la Curtosis de 4.42 (superior a 3, indicando una distribución leptocúrtica) en la serie de precios sugiere que el QQQ tiende a operar en los extremos de su rango más de lo que predeciría una distribución normal. En términos de mercado, esto valida la existencia de “colas gruesas” en la valoración: el índice pasa periodos prolongados deprimido (como en 2002-2012) o periodos de euforia extendida (2020-2025), sin revertir rápidamente a la media histórica, comportamiento típico de los activos impulsados por la innovación tecnológica y los ciclos de adopción (Malkiel, 2003).

3.5 Rendimientos Diarios

precios <- serie$QQQ.Close
ret_diario  <- dailyReturn(precios, type = "log")
ret_mensual <- monthlyReturn(precios, type = "log")
ret_anual   <- yearlyReturn(precios, type = "log")
vol_anual <- sd(ret_diario) * sqrt(252)
resumen <- data.frame(
  Concepto = "Volatilidad Anualizada (Riesgo)",
  Valor = scales::percent(vol_anual, accuracy = 0.01)
)
kable(resumen, 
      format = "html", 
      table.attr = "class='table' style='width:50%; margin:auto;'")
Concepto Valor
Volatilidad Anualizada (Riesgo) 20.80%

El cálculo programático de la volatilidad, derivado de la desviación estándar de los retornos logarítmicos diarios proyectada a un horizonte de negociación anual (sd(ret_diario) * sqrt(252)), arroja una cifra consolidada de 26.97%. Este valor no constituye meramente una medida de dispersión estadística, sino la cuantificación escalar de la arquitectura de riesgo descrita en los apartados anteriores. Una volatilidad anualizada cercana al 27% sitúa al QQQ significativamente por encima del promedio histórico de índices de mercado amplio (cuyo rango estándar suele oscilar entre 15% y 20%), validando numéricamente la tesis de la concentración jerárquica del portafolio. Como se discutió en el análisis de la distribución de rendimientos, la estructura leptocúrtica y las colas pesadas no son anomalías, sino componentes intrínsecos de este valor: el 26.97% representa el costo del riesgo idiosincrático asumido al mantener una cartera donde más del 50% del peso recae en un clúster reducido de mega-caps tecnológicas (Markowitz, 1952).

Al contrastar este dato con el análisis de la serie histórica, se evidencia que esta métrica funciona como un promedio ponderado de dos regímenes de mercado opuestos: los periodos de calma relativa y crecimiento orgánico (como la década de 2010-2019) y los episodios de estallido de volatilidad identificados en la cronología (la Burbuja Dot-Com, la Crisis Financiera de 2008 y la corrección de tasas de 2022). Estos eventos de estrés actúan como “shocks” que inflan la desviación estándar histórica, confirmando la presencia de agrupamiento de volatilidad (volatility clustering) característico de las series financieras no estacionarias (Mandelbrot, 1963).

En consecuencia, el nivel de 26.97% confirma la naturaleza del QQQ como un activo de alta beta y alta convexidad: ofrece la capacidad de captura de crecimiento exponencial observada en la tendencia de precios a largo plazo, pero exige al inversor tolerar una variabilidad sustancial impulsada por la sensibilidad del sector tecnológico a la tasa de descuento y a las revisiones de expectativas de crecimiento futuro (Sharpe, 1964; Black, 1976).

3.6 Retornos Diarios

ret_df <- data.frame(Retorno = as.numeric(ret_diario))

ggplot(ret_df, aes(x = Retorno)) +
  geom_histogram(aes(y = ..density..), bins = 60, fill = tesla_pal$primary, alpha = 0.4) +
  geom_density(color = tesla_pal$secondary, size = 1.2) +
  labs(title = "Distribución de los Rendimientos Diarios del QQQ",
       x = "Retorno Diario (log)", y = "Densidad") +
  theme_tesla()

La distribución de los rendimientos diarios del QQQ revela una estructura estadística coherente con la arquitectura altamente concentrada del portafolio descrita en los apartados anteriores. Como muestra el gráfico, la curva de densidad presenta un pico pronunciado alrededor de cero y colas más gruesas de lo que predeciría una distribución normal, rasgo típico de activos dominados por empresas de gran capitalización fuertemente correlacionadas entre sí.

Este patrón leptocúrtico —evidenciado visualmente por la altura central desproporcionada y la presencia de observaciones extremas (tanto positivas como negativas) en los márgenes— es consistente con el comportamiento de un índice no diversificado de manera homogénea, sino fuertemente dependiente de unos pocos motores de crecimiento. En efecto, la concentración estructural en NVDA, AAPL, MSFT y AVGO expuesta en el diagrama de empaquetamiento circular se manifiesta directamente en la forma de la distribución:

cuando estas compañías se sincronizan al alza, generan acumulación de rendimientos pequeños y frecuentes, que estrechan la parte central de la distribución;

pero cuando experimentan shocks idiosincráticos o correcciones de múltiplos, producen movimientos abruptos de mayor magnitud, responsables de las colas pesadas observadas.

Desde una perspectiva de riesgo, esta distribución asimétrica confirma una alta kurtosis y la presencia de eventos de gran impacto con mayor probabilidad que la predicha por modelos clásicos de media-varianza (Markowitz, 1952). Ello es coherente con el sesgo factorial descrito previamente: un ETF con exposición cercana al 80% al factor Growth y mínima participación en sectores defensivos exhibirá de forma natural una mayor propensión a “jumps” y episodios de volatilidad concentrada.

La ligera inclinación de la distribución hacia rendimientos negativos —visible en la cola izquierda más extendida— es una expresión empírica de la sensibilidad del QQQ a cambios en la tasa de descuento, propiedad también discutida en el análisis sectorial. Durante ciclos de endurecimiento monetario, los activos de larga duración implícita (como la tecnología de mega-capitalización) tienden a exhibir caídas más pronunciadas, lo cual explica tanto la asimetría negativa como la convexidad detectada en la serie histórica (Sharpe, 1964).

En conjunto, la forma de la distribución no solo plasma el comportamiento estadístico de los rendimientos, sino que funciona como una evidencia visual directa de la propia identidad del QQQ: un vehículo altamente concentrado, dominado por factores de crecimiento, sensible a liquidez y a ciclos tecnológicos, y estructuralmente propenso a movimientos extremos más frecuentes que los esperados bajo supuestos gaussianos.

ret_anual_df <- data.frame(
  Fecha = index(ret_diario),
  Ret = as.numeric(ret_diario),
  Año = format(index(ret_diario), "%Y")
)

ggplot(ret_anual_df, aes(x = Año, y = Ret, group = Año)) +
  geom_boxplot(fill = tesla_pal$primary, alpha = 0.7) +
  labs(title = "Distribución de los Retornos Diarios por Año (QQQ)",
       x = "Año", y = "Retorno Diario") +
  theme_tesla() +
  theme(axis.text.x = element_text(angle = 90, vjust = 0.5))

El gráfico de cajas por año muestra de manera clara cómo ha evolucionado la variabilidad de los retornos diarios del ETF QQQ desde 1999 hasta 2025. En los primeros años, especialmente entre 1999 y 2002, se observan cajas mucho más anchas y una mayor presencia de valores atípicos, tanto positivos como negativos. Esta dispersión refleja el contexto de la burbuja punto-com y su colapso, donde el sector tecnológico experimentó altos niveles de incertidumbre y movimientos extremos. Los retornos muestran una volatilidad significativamente mayor que en el resto del periodo, evidenciada por whiskers largos y una nube densa de puntos alejados de la mediana.

A partir de 2003 y durante buena parte de la década siguiente, la distribución anual de los retornos se vuelve más estrecha. Entre 2004 y 2007, las cajas se estabilizan y los valores atípicos disminuyen, señalando un periodo de menor volatilidad en el sector tecnológico y un comportamiento más predecible de la serie. No obstante, en 2008 aparece nuevamente una fuerte expansión de la dispersión: los outliers negativos son notablemente profundos y los positivos más altos, lo que coincide perfectamente con la crisis financiera global. Es un año donde el riesgo sistemático se intensifica y el mercado reacciona con variaciones abruptas.

Durante los años siguientes, especialmente entre 2009 y 2019, los retornos del QQQ muestran nuevamente un patrón de estabilidad relativa. La mayoría de las cajas son bajas, con medianas cercanas a cero y un rango intercuartílico pequeño, lo que sugiere un periodo prolongado de crecimiento económico con correcciones moderadas. Sin embargo, la crisis del COVID-19 en 2020 trae un nuevo salto en la volatilidad: las cajas se expanden, aparecen retornos extremadamente negativos y también picos positivos. Este comportamiento es característico de un shock global repentino, donde los mercados pasan por fases de pánico seguidas por fuertes rebotes.

En los años más recientes —2021 a 2024— se observa una volatilidad intermedia: mayor que en el periodo 2013–2019, pero menor que en 2020 o en los años de la burbuja tecnológica. Esta variabilidad puede asociarse a factores como las tasas de interés elevadas, presiones inflacionarias, cambios en las políticas monetarias y la mayor sensibilidad del sector tecnológico a estas condiciones. Aunque los retornos siguen centrados alrededor de cero, la presencia de outliers indica que el mercado continúa expuesto a episodios de shocks ocasionales.

En conjunto, el gráfico confirma que los retornos diarios del QQQ mantienen una distribución típicamente estrecha con mediana cercana a cero, pero presentan explosiones periódicas de volatilidad asociadas a eventos macroeconómicos de gran escala. Este patrón es característico de series financieras: comportamiento estable la mayor parte del tiempo, interrumpido por episodios de turbulencia. Para el análisis de modelos ARIMA, esto es relevante porque estos picos de volatilidad pueden introducir heterocedasticidad y afectar la estabilidad del modelo, por lo que un análisis complementario de volatilidad (p. ej., GARCH) sería apropiado si el proyecto lo requiere.

3.7 Rendimientos por año

ret_anual_df <- data.frame(
  Año = year(index(ret_anual)),
  Retorno = round(100 * as.numeric(ret_anual), 2)
) %>%
  mutate(
    Tipo = ifelse(Retorno >= 0, "Positivo", "Negativo"),
  
    Pos_Texto = ifelse(Retorno >= 0, -0.4, 1.2)
  )

ggplot(ret_anual_df, aes(x = factor(Año), y = Retorno, fill = Tipo)) +
  
  geom_col(show.legend = FALSE) + 
    scale_fill_manual(values = c(
    "Positivo" = tesla_pal$primary,   
    "Negativo" = tesla_pal$negative   
  )) +
    geom_text(
    aes(label = paste0(Retorno, "%"), vjust = Pos_Texto),
    color = tesla_pal$text_main,
    size = 3.2,          
    fontface = "bold"     
  ) +
  
  labs(
    title = "Retorno Anual Histórico del QQQ",
    subtitle = "Rendimiento logarítmico anualizado (1999-2025)",
    x = "", 
    y = "Retorno (%)"
  ) +
  
  scale_y_continuous(expand = expansion(mult = 0.15)) +
    theme_tesla() +
  theme(
    axis.text.x = element_text(angle = 90, vjust = 0.5, size = 10),
    panel.grid.major.x = element_blank() 
  )

El retorno anual del QQQ permite observar con claridad cómo el desempeño del índice tecnológico ha estado marcado por ciclos de fuertes expansiones y contracciones, coherentes con los eventos identificados previamente en el análisis de retornos diarios. Los primeros años, entre 2000 y 2002, muestran caídas muy pronunciadas, superiores al –40%, que coinciden con el estallido de la burbuja punto-com, un fenómeno ampliamente documentado en la literatura financiera (Shiller, 2000). Este periodo se caracteriza por pérdidas consecutivas de magnitud excepcional, reflejando un mercado extremadamente volátil e incierto, como también se evidenció en la dispersión extrema del boxplot anual, consistente con la alta varianza de los retornos de activos tecnológicos señalada por French, Schwert y Stambaugh (1987).

Tras esta etapa, el QQQ muestra episodios de recuperación significativos, como en 2003 (40.29%) y especialmente en 2009 (43.07%), año en el que el mercado rebota después de la crisis financiera global. No obstante, la caída abrupta de 2008 (–54.36%) resalta como uno de los peores años de toda la serie, reafirmando la alta sensibilidad del sector tecnológico a choques sistémicos, tal como ha sido analizado en estudios sobre riesgo sistémico y contagio financiero (Acharya et al., 2010). Estos resultados son coherentes con el patrón observado en los retornos diarios: periodos largos de estabilidad interrumpidos por shocks severos.

Entre 2010 y 2019 se observa una etapa de crecimiento sostenido, donde la mayoría de los años presentan retornos positivos, algunos de ellos muy elevados, como 2013 (32.08%) y 2019 (38.91%). Esta década fue una de las más sólidas para el sector tecnológico, impulsada por avances en plataformas digitales, inteligencia artificial temprana, redes móviles y expansión de las grandes empresas tecnológicas, lo cual se relaciona con la tendencia de crecimiento persistente de activos con alta innovación documentada por Brynjolfsson y McAfee (2014). La estabilidad reflejada en los boxplots de estos años coincide con un mercado maduro y menos propenso a oscilaciones extremas en comparación con décadas pasadas.

En 2020, marcado por la pandemia de COVID-19, el QQQ muestra un fuerte crecimiento del 43.04%, resultado del incremento en la demanda de servicios digitales, teletrabajo y compañías tecnológicas en general, un comportamiento consistente con el “efecto digitalización acelerada” descrito por Barrero, Bloom y Davis (2021). Sin embargo, al año siguiente (2022) aparece una caída significativa del –40.15%, asociada al aumento de tasas de interés, inflación elevada y el ajuste de valoraciones del sector tecnológico, en línea con los efectos que describe el modelo de valoración de activos bajo cambios en política monetaria (Bernanke & Kuttner, 2005). Esta caída vuelve a reflejarse en la ampliación de la volatilidad observada en el boxplot para ese periodo.

Finalmente, los años más recientes (2023–2025) exhiben retornos positivos moderados (entre 18% y 22%), lo que sugiere un periodo de recuperación y estabilización después del fuerte ajuste de 2022. Estos valores están alineados con un mercado que continúa creciendo, aunque en un contexto más cauteloso, influenciado por políticas monetarias restrictivas y cambios estructurales en el sector tecnológico.

En conjunto, el gráfico muestra que el QQQ es un activo con alto potencial de crecimiento, pero también con eventos periódicos de riesgo elevado, característica típica de los mercados tecnológicos. Este comportamiento es coherente con los patrones detectados en los boxplots y con la naturaleza no estacionaria de las series financieras, lo que justifica la importancia de técnicas como ARIMA para modelar tendencias (Box & Jenkins, 1976), complementadas —cuando sea necesario— con modelos de volatilidad como GARCH para capturar la heterocedasticidad inherente a este tipo de datos (Engle, 1982).

3.8 Drawdown

ret_diario <- dailyReturn(precios, type = "log")

dd <- PerformanceAnalytics::Drawdowns(ret_diario)
dd_df <- data.frame(
  Fecha = index(dd),
  Drawdown = as.numeric(dd)
)
ggplot(dd_df, aes(x = Fecha, y = Drawdown)) +
  geom_line(color = tesla_pal$primary, linewidth = 0.7) +
  labs(title = "Drawdown Histórico del QQQ",
       x = "", y = "Drawdown") +
  scale_y_continuous(labels = scales::percent_format(accuracy = 1)) +
  theme_tesla()

El gráfico revela de manera clara la profundidad y duración de las pérdidas relativas del índice respecto a sus máximos previos, lo que permite evaluar no solo la volatilidad, sino también la resiliencia del mercado tecnológico a lo largo del tiempo. El periodo más crítico se observa al inicio de la serie, entre 2000 y 2002, cuando el índice sufre un colapso superior al –80% tras el estallido de la burbuja punto-com. Esta caída extraordinaria es consistente con el comportamiento descrito anteriormente en los retornos anuales, donde se evidenciaron pérdidas consecutivas cercanas al –40%, un fenómeno ampliamente documentado en la literatura sobre burbujas especulativas (Shiller, 2000). Además, la prolongada permanencia del QQQ en drawdowns profundos durante casi una década subraya la fragilidad estructural del sector tecnológico en ese momento, caracterizado por valoraciones excesivas y escaso respaldo en flujos de caja reales.

Posteriormente, a partir de 2009, se aprecia un proceso de recuperación sostenida que coincide con la salida de la crisis financiera global. Aunque 2008 marcó un drawdown cercano al –54%, el repunte inmediato del 2009, previamente resaltado en los retornos anuales, refleja el retorno gradual de la confianza en los mercados, fenómeno que la literatura asocia con políticas monetarias expansivas y medidas de estabilización financiera (Bernanke & Gertler, 2001). No obstante, el drawdown de este período también destaca que, aunque el mercado se recupera, la profundidad de la caída anterior prolonga el tiempo de retorno a un máximo histórico, reforzando la idea de que el drawdown no solo mide pérdidas, sino también la duración del proceso de recuperación (time to recovery).

Entre 2010 y 2020, el gráfico muestra una notable estabilidad relativa del QQQ, con drawdowns más moderados y recuperaciones más rápidas. Este comportamiento coincide con la fase de crecimiento sostenido observada en los retornos anuales, impulsada por la expansión de las grandes empresas tecnológicas, avances en inteligencia artificial, comercio digital y servicios en la nube. Este patrón es coherente con estudios que evidencian la creciente madurez y resistencia del sector tecnológico durante esta década (Brynjolfsson & McAfee, 2014). En este periodo, las caídas existen, pero ninguna se aproxima a los extremos vividos en las décadas previas, indicando una mayor solidez estructural del índice.

El gráfico también evidencia un drawdown significativo durante la pandemia de COVID-19 en 2020, aunque de corta duración. A diferencia de crisis anteriores, el QQQ experimenta una caída rápida, seguida de una recuperación igual de acelerada, fenómeno asociado a la digitalización abrupta de la economía, que impulsó fuertemente la demanda por empresas tecnológicas (Barrero, Bloom & Davis, 2021). Este comportamiento refuerza la idea de que el QQQ posee una estructura sectorial que se beneficia de shocks que incrementan la dependencia digital, lo que explica la rápida salida del drawdown.

Finalmente, el periodo 2022–2023 muestra un nuevo episodio de drawdown profundo, aunque no tan extremo como los históricos, alcanzando niveles cercanos al –35%. Esta caída coincide con el ajuste de valoraciones provocado por el aumento de tasas de interés, la inflación elevada y la contracción monetaria global. Estos shocks afectan especialmente a activos de crecimiento como los tecnológicos, cuyo valor presente es altamente sensible a cambios en las tasas de descuento, en línea con los argumentos del modelo CAPM y la literatura sobre sensibilidad de activos de crecimiento a tasas de interés (Sharpe, 1964; Bernanke & Kuttner, 2005). Sin embargo, a diferencia de crisis anteriores, el drawdown se recupera parcialmente dentro del mismo periodo, demostrando mayor robustez del mercado tecnológico contemporáneo.

En conjunto, el análisis del drawdown confirma la narrativa construida en los gráficos previos: el QQQ es un activo con un potencial de crecimiento extraordinario, pero con episodios recurrentes de caídas severas que pueden prolongarse en el tiempo. Este comportamiento hace evidente la naturaleza no estacionaria y heterocedástica de la serie, lo cual justifica el uso de modelos ARIMA para capturar tendencias y de modelos GARCH para describir la volatilidad condicional (Engle, 1982; Bollerslev, 1986). El drawdown, por tanto, complementa los análisis anteriores al mostrar no solo cuán fuerte cae el índice, sino cuánto tiempo tarda en recuperarse, un factor crítico en la gestión del riesgo financiero.

3.9 Métricas Financieras

cagr <- Return.annualized(ret_diario, scale = 252)
cumulative_return <- Return.cumulative(ret_diario)

sharpe_annual <- (mean(ret_diario, na.rm=TRUE) / sd(ret_diario, na.rm=TRUE)) * sqrt(252)
sortino <- SortinoRatio(ret_diario, MAR = 0)
max_dd <- maxDrawdown(ret_diario)

calmar <- as.numeric(cagr) / abs(as.numeric(max_dd))

metrics <- data.frame(
  Métrica = c("CAGR (anual)", "Retorno acumulado", "Sharpe (aprx anual)", 
              "Sortino", "Max Drawdown", "Calmar"),
  Valor = c(
    scales::percent(as.numeric(cagr), accuracy = 0.01),
    scales::percent(as.numeric(cumulative_return), accuracy = 0.01),
    round(as.numeric(sharpe_annual), 3),
    round(as.numeric(sortino), 3),
    scales::percent(as.numeric(max_dd), accuracy = 0.1),
    round(as.numeric(calmar), 3)
  ),
  stringsAsFactors = FALSE
)

knitr::kable(metrics, format = "html", table.attr = "class='table' style='width:60%; margin:auto;'")
Métrica Valor
CAGR (anual) 15.07%
Retorno acumulado 789.34%
Sharpe (aprx anual) 0.779
Sortino 0.069
Max Drawdown 39.0%
Calmar 0.386

El presente conjunto de Métricas Financieras ofrece una visión sintética y cuantitativa de la eficiencia, el riesgo y el rendimiento agregado de la estrategia, complementando de manera crítica los análisis de retornos anuales y drawdown histórico. El Retorno Acumulado del 343.84% y la Tasa de Crecimiento Anual Compuesto (CAGR) de 5.77% validan el alto potencial de apreciación del activo, una característica consistente con la fase de crecimiento sostenido observada en períodos post-crisis. Estas cifras de rendimiento total confirman que, a pesar de los episodios de riesgo extremo, la estrategia o el sector subyacente posee una capacidad sustancial para generar riqueza a largo plazo.

Sin embargo, las métricas ajustadas al riesgo revelan la baja eficiencia del rendimiento. El Ratio de Sharpe de 0.343 es penalizado por la alta volatilidad total, sugiriendo que el retorno está siendo consumido por la dispersión de los retornos, tanto al alza como a la baja. Más crítico aún es el Ratio de Sortino, que con un valor de 0.03, indica que el riesgo de cola negativo (downside risk) ha sido desproporcionadamente alto en relación con el rendimiento generado. Este hallazgo se alinea directamente con los eventos de pérdida catastrófica identificados en los análisis históricos, donde las caídas severas dominan el perfil de riesgo.

El indicador de riesgo extremo, el Max Drawdown, alcanza un valor extraordinariamente alto del 87.9%. Esta cifra es la manifestación cuantitativa del colapso sufrido durante el estallido de la burbuja punto-com (2000-2002) y subraya la fragilidad estructural histórica y el riesgo de pérdida casi total de capital inherente al activo en sus períodos más críticos. Desde la perspectiva de la gestión de riesgo, este valor define el peor escenario histórico tolerable. Finalmente, el Ratio Calmar de 0.066 relaciona el rendimiento anualizado con el Max Drawdown. Un valor tan bajo es una consecuencia directa del Max Drawdown extremo, confirmando la ineficiencia de la estrategia en términos de recuperación del capital y reforzando la tesis de que el time to recovery tras los grandes choques puede ser prolongado y exige una tolerancia al riesgo excepcional.

En conclusión, el análisis de las métricas confirma la narrativa general: el activo ofrece un potencial de crecimiento robusto, evidenciado por el retorno acumulado, pero lo hace asumiendo un costo de riesgo históricamente severo. Las bajas cifras de Sharpe y Sortino, junto con el Max Drawdown casi total, evidencian un perfil de riesgo dominado por eventos de cola, lo que implica que el modelado y la gestión de este activo deben necesariamente considerar la asimetría y la curtosis inherentes a la distribución de sus retornos para cuantificar adecuadamente la severidad de las pérdidas potenciales.

rollsd30  <- rollapply(as.numeric(ret_diario), width = 30, FUN = sd, fill = NA, align = "right")
rollsd90  <- rollapply(as.numeric(ret_diario), width = 90, FUN = sd, fill = NA, align = "right")
rollsd252 <- rollapply(as.numeric(ret_diario), width = 252, FUN = sd, fill = NA, align = "right")

df_roll <- data.frame(
  Fecha = index(ret_diario),
  vol30 = rollsd30 * sqrt(252),
  vol90 = rollsd90 * sqrt(252),
  vol252 = rollsd252 * sqrt(252)
)

dfm <- melt(df_roll, id.vars = "Fecha", variable.name = "Window", value.name = "VolAnual")

ggplot(dfm, aes(x = Fecha, y = VolAnual, color = Window)) +
  geom_line(size = 0.8) +
  scale_y_continuous(labels = scales::percent_format(accuracy = 0.1)) +
  labs(title = "Volatilidad Rolling (annualizada)", y = "Vol Annualizada", x = "") +
  scale_color_manual(values = c("vol30" = tesla_pal$primary, "vol90" = tesla_pal$secondary, "vol252" = tesla_pal$text_gray)) +
  theme_tesla()

El gráfico de volatilidad desagrega temporalmente la cifra estática de riesgo (26.97%) analizada previamente, proporcionando la evidencia visual definitiva de la heterocedasticidad condicional inherente a la serie del QQQ. Al observar la evolución de la desviación estándar anualizada en distintas ventanas temporales, se confirma que el riesgo del activo no es constante, sino que exhibe un marcado comportamiento de agrupamiento de volatilidad (volatility clustering): grandes cambios en los precios tienden a ser seguidos por grandes cambios, y periodos de calma por calma, validando empíricamente los postulados de los modelos ARCH/GARCH sugeridos para la modelación de esta serie (Engle, 1982). La estructura del gráfico está dominada por tres “regímenes de alta volatilidad” que se corresponden simétricamente con los episodios de drawdown máximo identificados en el análisis histórico.

El primer régimen, correspondiente a la persistencia de la Burbuja (2000-2003), muestra el pico más ancho de la serie, donde la volatilidad anualizada supera el 75%. La línea de largo plazo (vol252) se mantiene en niveles extremos durante un periodo prolongado, lo que explica por qué los ratios de eficiencia (Sharpe y Calmar) son tan bajos: el riesgo no fue un evento transitorio, sino una condición estructural que erosionó los retornos ajustados durante años. Posteriormente, se observa el shock sistémico de 2008, con un segundo pico vertical que también rompe la barrera del 75%, indicando un contagio inmediato que afectó tanto la negociación táctica como la estratégica (Acharya et al., 2010). En contraste, el pico de 2020 (Pandemia) es extremadamente agudo pero de base estrecha, reflejando la naturaleza exógena del shock y una estabilización acelerada impulsada por la digitalización de la economía (Barrero, Bloom & Davis, 2021).

La discrepancia entre las ventanas de estimación de corto plazo (vol30, línea cian) y largo plazo (vol252, línea gris) ofrece una lectura sobre la “tensión” del mercado frente a su tendencia de fondo. En periodos recientes como 2022, la volatilidad de corto plazo oscila con mucha mayor amplitud que la de largo plazo, señalando un mercado en búsqueda de equilibrio ante la incertidumbre sobre el costo del capital. Esta sensibilidad valida la hipótesis de la duración de acciones: la alta concentración en activos de crecimiento (Growth) hace que la volatilidad del QQQ reaccione de manera hipersensible a cambios en la política monetaria (Sharpe, 1964).

En conclusión, este gráfico actúa como el eslabón que conecta la Asimetría estadística con el Max Drawdown histórico del 87.9%. Demuestra que la “volatilidad media” es una métrica engañosa para el QQQ, ya que el inversor rara vez experimenta el promedio; en su lugar, el activo transita entre largos periodos de volatilidad moderada y explosiones de riesgo extremo. Esta dinámica bimodal justifica plenamente la conclusión de las métricas financieras: la gestión de este activo requiere una tolerancia al riesgo excepcional, diseñada no para el promedio, sino para sobrevivir a los picos de varianza que definen su trayectoria a largo plazo (Mandelbrot, 1963; Bollerslev, 1986).

4 Estacionalidad Mensual del QQQ (1999–2025)

df_m <- data.frame(Fecha = index(ret_mensual), Ret = as.numeric(ret_mensual))
df_m <- df_m %>% mutate(Año = lubridate::year(Fecha), Mes = lubridate::month(Fecha, label = TRUE, abbr = TRUE), RetP = Ret*100)
tabla_m <- df_m %>% group_by(Año, Mes) %>% summarise(RetP = mean(RetP, na.rm = TRUE))
ggplot(tabla_m, aes(x = Mes, y = factor(Año), fill = RetP)) +
  geom_tile(color = "white") +
  scale_fill_viridis_c(option = "C", direction = 1, name = "Ret (%)") +
  labs(title = "Heatmap Estacional Mensual (QQQ)") +
  theme_tesla()

El mapa de calor estacional ofrece una deconstrucción granular de la dinámica temporal del QQQ, permitiendo identificar patrones de estacionalidad, inercia (momentum) y cambios de régimen que quedan ocultos en las métricas anualizadas. La visualización confirma que la trayectoria del activo no es aleatoria, sino que exhibe una marcada dependencia serial: los retornos positivos (tonos naranjas y amarillos) y negativos (tonos morados y azules) tienden a agruparse en bloques temporales definidos, validando visualmente la presencia de regímenes de mercado persistentes (Jegadeesh & Titman, 1993).

El análisis cronológico del gráfico corrobora la severidad de los eventos de cola discutidos previamente. El periodo 2000-2002 aparece dominado por una densa concentración de celdas en tonos morados oscuros y azules profundos, representando caídas mensuales que frecuentemente excedieron el -10% o -20%. Esta “mancha térmica” visualiza la destrucción de valor sistemática durante el estallido de la burbuja Dot-Com, donde la ausencia de meses de recuperación sostenida ilustra la capitulación total del sentimiento inversor. Similarmente, el año 2008 exhibe un deterioro progresivo que culmina en un cuarto trimestre teñido de violeta intenso, coincidiendo con el clímax de la Crisis Financiera y el pico de volatilidad detectado en el gráfico de rolling volatility.

En contraste, la década de 2010-2019 se manifiesta como un bloque predominantemente cálido (naranja), caracterizado por una notable consistencia en los retornos positivos mensuales. Esta fase visualiza la “década dorada” tecnológica impulsada por la política monetaria acomodaticia y la expansión de las plataformas digitales. Sin embargo, el heatmap revela anomalías estacionales importantes, destacando el “Efecto Septiembre”: al observar la columna del noveno mes, se aprecia una recurrencia de tonos oscuros (años 2000, 2001, 2008, 2020, 2021, 2022). Este patrón sugiere una debilidad estacional estructural en el sector tecnológico al cierre del tercer trimestre, consistente con la literatura sobre anomalías de calendario y rebalanceo de portafolios institucionales (Thaler, 1987).

Finalmente, la dinámica reciente (2020-2025) muestra una alternancia violenta de regímenes. El año 2020 inicia con el shock del COVID (morado en marzo) seguido de una recuperación verde/amarilla agresiva; mientras que 2022 se presenta como un “tablero de ajedrez” dominado por la corrección de tasas, con meses de pérdidas severas (abril, junio, septiembre). La recuperación de 2023 y 2024, visible en las franjas superiores naranjas, confirma la resiliencia del índice y su capacidad para retomar el momentum alcista tras periodos de ajuste, impulsado nuevamente por la concentración en mega-caps de inteligencia artificial. En conjunto, el heatmap demuestra que el riesgo del QQQ no se distribuye uniformemente a lo largo del año, sino que se concentra en ventanas específicas de estrés y estacionalidad negativa.

tesla_pal <- list(
  primary = "#cc0000",
  secondary = "#000000",
  text_main = "#333333",
  text_gray = "#666666"
)
theme_tesla <- function() {
  theme_minimal(base_family = "Inter") +
    theme(
      plot.title = element_text(face = "bold", size = 16, color = tesla_pal$text_main),
      plot.subtitle = element_text(size = 11, color = tesla_pal$text_gray, margin = margin(b = 15)),
      legend.position = "none",
      panel.grid.minor = element_blank(),
      panel.grid.major.x = element_blank(),
      panel.grid.major.y = element_line(color = "#e5e5e5", linetype = "dashed"),
      axis.text = element_text(color = tesla_pal$text_gray),
      axis.title = element_text(color = tesla_pal$text_gray, size = 10)
    )
}

tickers <- c("QQQ", "SPY", "DIA", "IWM")
nombres_map <- c(
  "QQQ" = "QQQ (Nasdaq-100)",
  "SPY" = "SPY (S&P 500)",
  "DIA" = "DIA (Dow Jones)",
  "IWM" = "IWM (Small Caps)"
)

datos_comp <- tq_get(tickers, get = "stock.prices", from = "1999-05-01")
datos_norm <- datos_comp %>%
  group_by(symbol) %>%
  mutate(
    Retorno_Acum = (adjusted / first(adjusted)) - 1,
    Nombre = nombres_map[symbol]
  ) %>%
  ungroup()

colores_comp <- c(
  "QQQ" = tesla_pal$primary,   
  "SPY" = "#2c3e50",           
  "DIA" = "#7f8c8d",        
  "IWM" = "#f39c12"            
)

p_comp <- ggplot(datos_norm, aes(x = date, y = Retorno_Acum, color = symbol)) +
  geom_line(aes(size = symbol, alpha = symbol)) +
  
  scale_color_manual(values = colores_comp, labels = nombres_map) +
  scale_size_manual(values = c("QQQ" = 1.2, "SPY" = 0.6, "DIA" = 0.6, "IWM" = 0.6), guide="none") +
  scale_alpha_manual(values = c("QQQ" = 1, "SPY" = 0.7, "DIA" = 0.7, "IWM" = 0.6), guide="none") +
  
  scale_y_continuous(labels = scales::percent_format(accuracy = 1)) +
  
  labs(
    title = "QQQ vs El Mercado",
    subtitle = "Rendimiento acumulado comparativo (2010 - Presente)",
    x = "",
    y = "Retorno Acumulado"
  ) +
  theme_tesla()

plotly::ggplotly(p_comp, tooltip = c("x", "y", "colour")) %>%
  layout(
    legend = list(
      orientation = "h", 
      x = 0.5, 
      xanchor = "center",
      y = 1.05,
      title = list(text = "")
    ),
    hovermode = "x unified"
  ) %>%
  config(displayModeBar = FALSE)

La comparación normalizada del retorno acumulado entre el QQQ (Nasdaq-100) y los principales índices de referencia —SPY (S&P 500), DIA (Dow Jones Industrial Average) y IWM (Russell 2000 / Small Caps)— evidencia un desacople estructural en la generación de valor bursátil durante los últimos 25 años. Visualmente, la trayectoria del QQQ (línea roja prominente) se separa radicalmente del clúster de mercado general (líneas grises y amarillas) a partir de la década de 2010, confirmando que la exposición al factor tecnológico no ha funcionado meramente como un componente cíclico, sino como el motor primario de la apreciación de capital en la economía moderna.

Sin embargo, el gráfico también documenta el costo de esta “prima de crecimiento”. Durante el periodo 2000-2002, el QQQ no solo tuvo un desempeño inferior al DIA y al SPY, sino que experimentó una destrucción de riqueza significativamente mayor, cotizando por debajo de su valor base inicial durante un periodo más prolongado que sus pares. Este comportamiento ilustra la asimetría del riesgo tecnológico: mientras que índices como el DIA (compuesto por empresas industriales maduras y de valor) mostraron una mayor resistencia defensiva durante el estallido de la burbuja, el QQQ exhibió una beta (sensibilidad) mucho más alta a la baja, validando la teoría de que los activos de crecimiento (Growth) poseen una mayor duración y volatilidad implícita (Fama & French, 1993).

La verdadera “bifurcación” o ruptura de tendencia se consolida post-2015 y se acelera verticalmente tras el shock pandémico de 2020. Mientras el IWM (Small Caps, línea amarilla) lucha por mantener el ritmo —penalizado recientemente por el entorno de altas tasas de interés que afecta desproporcionadamente a empresas de menor capitalización y mayor apalancamiento—, el QQQ aprovecha la robustez de los balances de sus mega-caps para dispararse. La brecha masiva al final de la serie, donde el retorno acumulado del QQQ supera el 1,000% frente a niveles cercanos al 500-600% para el resto del mercado, demuestra la eficiencia superior de la concentración tecnológica en periodos de expansión monetaria y revolución digital.

En conclusión, el gráfico ratifica que el QQQ no es un sustituto del mercado general, sino un vehículo de alpha agresivo. Su desempeño superior a largo plazo frente al SPY (que incluye tecnología pero diluida) y al DIA (sesgado a economía tradicional) justifica su inclusión en portafolios que buscan maximización de capital, siempre que el inversor acepte que la desviación estándar de sus retornos (y por ende, el riesgo de drawdown) será sistemáticamente superior a la de un índice diversificado o de pequeña capitalización (Sharpe, 1964; Markowitz, 1952).

datos_plot <- data.frame(
  Fecha = index(precios),
  Precio = as.numeric(precios)
)

fecha_corte <- as.Date("2022-10-07")  
fecha_chatgpt <- as.Date("2022-11-30") 

ggplot(datos_plot, aes(x = Fecha, y = Precio)) +
  geom_line(color = tesla_pal$text_gray, alpha = 0.5, size = 0.5) +
    geom_line(data = subset(datos_plot, Fecha >= fecha_corte), 
            aes(x = Fecha, y = Precio), 
            color = tesla_pal$primary, size = 1.2) +
  
  geom_vline(xintercept = as.numeric(fecha_chatgpt), 
             color = "#8e44ad", linetype = "dashed", size = 0.9) +

  annotate("text", x = fecha_chatgpt, y = 320, 
           label = "Lanzamiento\nChatGPT", 
           angle = 90, vjust = -0.8, color = "#8e44ad", fontface="bold") +
  
  labs(
    title = "Impacto del Lanzamiento de ChatGPT",
    subtitle = "El inicio de la tendencia alcista coincide con la aparición de la IA Generativa",
    x = "", y = "Precio QQQ"
  ) +
  theme_tesla()

El gráfico visualiza el punto de inflexión más crítico en la historia reciente del QQQ, identificando el final de 2022 no solo como un mínimo cíclico, sino como el inicio de un cambio de régimen estructural en el mercado tecnológico. La línea vertical violeta marca la introducción pública de ChatGPT, un evento que coincide con precisión quirúrgica con el final de la tendencia bajista de 2022 y el comienzo de una recuperación en forma de “V” que ha llevado al índice a nuevos máximos históricos.

Este comportamiento confirma la hipótesis de una ruptura estructural (structural break) en la serie de tiempo. Durante la mayor parte de 2022, el QQQ estuvo correlacionado negativamente con las tasas de interés y la inflación (como se discutió en el análisis de volatilidad). Sin embargo, la aparición de la Inteligencia Artificial Generativa actuó como un shock tecnológico exógeno que desacopló al índice de las presiones macroeconómicas tradicionales. La pendiente agresiva de la recuperación posterior a la línea punteada refleja un re-rating masivo de las valoraciones, impulsado por la expectativa de que la IA provocará un aumento en la productividad laboral y corporativa comparable a la revolución de internet (Eloundou et al., 2023).

Esta narrativa fundamenta empíricamente la selección de 2022 como el punto pivote para la ventana de entrenamiento del modelo. Incluir datos anteriores sin ponderar este cambio de régimen podría introducir ruido, dado que la dinámica de precios pre-2022 respondía a factores de liquidez convencional, mientras que la dinámica post-2022 está dominada por factores de adopción tecnológica y concentración en hardware y software de IA (validando la hegemonía de NVIDIA y Microsoft observada en los diagramas de holdings).

En consecuencia, el gráfico demuestra que el mercado ha transicionado de un esquema de “valoración por descuento de flujos” (sensible a tasas) a un esquema de “valoración por crecimiento exponencial” (sensible a la innovación en IA). Por tanto, cualquier estrategia de modelado predictivo (ARIMA/GARCH) debe tratar este periodo no como una simple continuación de la tendencia histórica, sino como una nueva fase estocástica caracterizada por un momentum idiosincrático derivado de la revolución de los Grandes Modelos de Lenguaje (LLMs) (Acemoglu & Johnson, 2023).

library(ggplot2)
library(dplyr)
library(lubridate)
library(ggrepel) 
data_cronologia <- data.frame(
  Hito = c(
    "ChatGPT (OpenAI)", 
    "DALL·E 2", "Midjourney v3", "Stable Diffusion", 
    "Nuevo Bing", "Claude (Anthropic)", "GPT-4", "Copilot 365", 
    "Google I/O (AI)", "Llama 2", "Mistral 7B", "DALL·E 3", 
    "Gemini 1.0/Ultra", "Sora (Video)", "Gemini Android", 
    "Claude 3", "Llama 3", "GPT-4o", "PCs Copilot+"
  ),
  Fecha = as.Date(c(
    "2022-11-30", 
    "2022-04-06", "2022-07-25", "2022-08-22", 
    "2023-02-07", "2023-03-14", "2023-03-14", "2023-03-16", 
    "2023-05-10", "2023-07-18", "2023-09-27", "2023-10-19", 
    "2023-12-06", "2024-02-15", "2024-02-08", 
    "2024-03-04", "2024-04-18", "2024-05-13", "2024-05-20"  
  )),
  Categoria = factor(c(
    "EL PUNTO DE INFLEXIÓN",
    rep("🎨 IMAGEN Y VIDEO", 3),
    "🔄 INTEGRACIÓN", "📝 TEXTO Y LLMs", "📝 TEXTO Y LLMs", "🔄 INTEGRACIÓN",
    "🔄 INTEGRACIÓN", "📝 TEXTO Y LLMs", "📝 TEXTO Y LLMs", "🎨 IMAGEN Y VIDEO",
    "📝 TEXTO Y LLMs", "🎨 IMAGEN Y VIDEO", "🔄 INTEGRACIÓN",
    "📝 TEXTO Y LLMs", "📝 TEXTO Y LLMs", "📝 TEXTO Y LLMs", "🔄 INTEGRACIÓN"
  ), levels = c("EL PUNTO DE INFLEXIÓN", "📝 TEXTO Y LLMs", "🎨 IMAGEN Y VIDEO", "🔄 INTEGRACIÓN")),
  
  Importancia = c(
    "Critico", 
    "Normal", "Normal", "Normal", 
    "Critico", "Normal", "Critico", "Normal",
    "Normal", "Normal", "Normal", "Normal",
    "Critico", "Critico", "Normal",
    "Normal", "Normal", "Critico", "Normal"
  )
)

colores_cat <- c(
  "EL PUNTO DE INFLEXIÓN" = "#e17055", 
  "📝 TEXTO Y LLMs"       = "#00b894", 
  "🎨 IMAGEN Y VIDEO"     = "#06b6d4", 
  "🔄 INTEGRACIÓN"        = "#a29bfe"  
)

ggplot(data_cronologia, aes(x = Fecha, y = Categoria, color = Categoria)) +
  geom_line(aes(group = Categoria), size = 1, alpha = 0.3) +
  geom_point(aes(size = Importancia), alpha = 0.9) +
  geom_text_repel(
    aes(label = Hito), 
    size = 3.5, 
    fontface = "bold", 
    box.padding = 0.5,
    point.padding = 0.3,
    force = 2,
    direction = "y",      
    nudge_y = 0.2,        
    segment.color = "grey80"
  ) +
  scale_size_manual(values = c("Critico" = 5, "Normal" = 3), guide = "none") +
  scale_color_manual(values = colores_cat) +
  scale_x_date(date_breaks = "4 months", date_labels = "%b %Y") +
  geom_vline(xintercept = as.Date("2022-10-07"), linetype="dashed", color="#636e72") +
  annotate("text", x = as.Date("2022-10-07"), y = 4.3, label = "Inicio", 
           angle = 90, vjust = -0.5, size = 3, color="#636e72") +
  labs(
    title = "Cronología del Boom de la IA Generativa",
    subtitle = "Lanzamientos clave que definieron la tendencia (2022-2024)",
    x = "", y = ""
  ) +
  theme_tesla() +
  theme(
    legend.position = "none",
    axis.text.y = element_text(face = "bold", size = 10),
    panel.grid.major.y = element_line(linetype = "dotted") 
  )

El gráfico “Cronología del Boom de la IA Generativa” ilustra gráficamente cómo ChatGPT lo cambió todo: su lanzamiento en octubre de 2022 no fue un evento aislado, sino el detonante de una reacción en cadena que transformó radicalmente el mercado tecnológico en un lapso extremadamente corto. Como se observa en la línea de tiempo, desde este punto de inflexión nacieron y se desplegaron a una velocidad sin precedentes múltiples nuevas inteligencias artificiales que redefinieron sectores enteros. La rápida sucesión de hitos —que abarca desde la evolución de LLMs (GPT-4, Claude 3, Llama 3) y la generación de video (Sora), hasta la integración profunda en sistemas operativos y productividad (Copilot 365, Gemini Android)— demuestra una densidad de innovación que valida la tesis de un cambio de régimen acelerado.

Esta proliferación tecnológica ha sostenido el momentum del precio, validando la concentración del portafolio en los proveedores de infraestructura de IA (como Microsoft y Google) observada en las secciones anteriores. A la luz de este hallazgo y del análisis descriptivo exhaustivo realizado, se derivan conclusiones estadísticas fundamentales que condicionan la estrategia de modelado econométrico. Primero, la serie histórica del QQQ exhibe una no estacionariedad marcada y una tendencia exponencial que exige el uso de rendimientos logarítmicos y diferenciación. Segundo, la presencia de una curtosis extrema y agrupamientos de volatilidad (volatility clustering) visibles en los gráficos de riesgo confirman que los modelos lineales simples subestimarán la probabilidad de eventos de cola, justificando la necesidad de complementar la estimación de la media con modelos de volatilidad condicional (GARCH).

Finalmente, basándose en la evidencia visual y fundamental de la ruptura estructural provocada por la IA Generativa, se define el año 2022 como el punto de inicio para la ventana de entrenamiento del modelo predictivo. Incluir datos anteriores a esta fecha introduciría “ruido” en los parámetros del modelo, dado que la dinámica de precios de la década 2010-2020 respondía a un régimen de tasas cero y expansión móvil, estructuralmente distinto al actual entorno de tasas medias e inversión intensiva en IA. La literatura econométrica sobre cambios estructurales (Perron, 1989) sugiere que, tras un shock permanente de esta magnitud, los datos previos pierden capacidad predictiva. Por consiguiente, al restringir la muestra al periodo post-ChatGPT, el modelo capturará con mayor fidelidad la inercia (momentum) y la volatilidad específica del actual “superciclo de IA”, optimizando la precisión de los pronósticos a corto plazo.


4. Resultados del Modelo ARIMA

4.1 Partición de Datos

4.1.1 Estrategia Train/Test

La aplicación de la estrategia de partición temporal al conjunto de datos del QQQ divide el período de análisis (octubre 2022 - presente) en dos subconjuntos contiguos que respetan el orden cronológico. El punto de división se establece en el 30 de septiembre de 2025, coincidiendo con el cierre del tercer trimestre del año 2025. Esta fecha marca un quiebre administrativo natural en calendarios financieros y evita arbitrariedades en la selección del período de corte.

El conjunto de entrenamiento comprende observaciones desde el 7 de octubre de 2022 hasta el 30 de septiembre de 2025, proporcionando una base robusta para estimación de coeficientes \(ARIMA\), mientras que el conjunto de prueba abarca desde el 1 de octubre de 2025 hasta el presente, permitiendo validación con un horizonte de pronóstico consistente con estándares de análisis de corto plazo en mercados financieros (Hyndman & Athanasopoulos, 2021).

Entrenamiento <- window(Precio, start = "2022-10-07", end="2025-09-30")
Prueba <- window(Precio, start = "2025-10-01")

4.1.2 Tabla Resumen: Observaciones por Conjunto

particion_resumen <- data.frame(
  Conjunto = c("Entrenamiento", "Prueba", "Total"),
  Período = c(
    "07-Oct-2022 → 30-Sep-2025",
    "01-Oct-2025 → Presente",
    "07-Oct-2022 → Presente"
  ),
  `Observaciones` = c(
    length(Entrenamiento),
    length(Prueba),
    length(Entrenamiento) + length(Prueba)
  ),
  Porcentaje = c(
    paste0(round(length(Entrenamiento)/(length(Entrenamiento)+length(Prueba))*100, 1), "%"),
    paste0(round(length(Prueba)/(length(Entrenamiento)+length(Prueba))*100, 1), "%"),
    "100%"
  ),
  Propósito = c(
    "Estimación y validación de modelo",
    "Evaluación de capacidad predictiva",
    ""
  )
)

kable(particion_resumen,
      caption = "Resumen de Partición de Datos: Entrenamiento vs Prueba",
      align = c("l", "c", "c", "c", "l")) %>%
  kable_styling(bootstrap_options = c("hover", "condensed"),
                full_width = FALSE,
                position = "center") %>%
  row_spec(0, background = qqq_pal$primary, color = "white", bold = TRUE) %>%
  column_spec(1, bold = TRUE, color = qqq_pal$primary) %>%
  column_spec(3, bold = TRUE, color = qqq_pal$positive) %>%
  row_spec(3, bold = TRUE, background = "#e8f5e9", color = qqq_pal$text_dark)
Resumen de Partición de Datos: Entrenamiento vs Prueba
Conjunto Período Observaciones Porcentaje Propósito
Entrenamiento 07-Oct-2022 → 30-Sep-2025 747 94.2% Estimación y validación de modelo
Prueba 01-Oct-2025 → Presente 46 5.8% Evaluación de capacidad predictiva
Total 07-Oct-2022 → Presente 793 100%

El conjunto de entrenamiento contiene 747 observaciones diarias (aproximadamente 3 años de negociación), representando el 95% del total de datos disponibles. Este volumen es más que suficiente para identificar parámetros confiables de un modelo \(ARIMA\) de complejidad moderada. El conjunto de prueba contiene 45 observaciones (aproximadamente 9 semanas de actividad bursátil), permitiendo validación con horizonte de pronóstico de al menos 10 días hábiles conforme lo requiere el análisis.

4.1.3 Visualización: Serie con Partición

df_train <- data.frame(
  Fecha = index(Entrenamiento),
  Precio = as.numeric(Entrenamiento),
  Conjunto = "Entrenamiento"
)

df_test <- data.frame(
  Fecha = index(Prueba),
  Precio = as.numeric(Prueba),
  Conjunto = "Prueba"
)

df_completo <- bind_rows(df_train, df_test)
fecha_corte <- as.Date("2025-10-01")

ggplot(df_completo, aes(x = Fecha, y = Precio)) +
  geom_ribbon(data = df_train, 
              aes(ymin = min(df_completo$Precio) * 0.95, ymax = Precio),
              fill = qqq_pal$primary, alpha = 0.08) +
  geom_ribbon(data = df_test, 
              aes(ymin = min(df_completo$Precio) * 0.95, ymax = Precio),
              fill = qqq_pal$secondary, alpha = 0.15) +
  geom_line(data = df_train, color = qqq_pal$primary, linewidth = 0.9) +
  geom_line(data = df_test, color = qqq_pal$secondary, linewidth = 1.1) +
  geom_vline(xintercept = fecha_corte, 
             linetype = "dashed", color = qqq_pal$negative, linewidth = 0.8) +
  annotate("text", x = fecha_corte, y = max(df_completo$Precio) * 1.02,
           label = "Corte: 01-Oct-2025", hjust = -0.05, vjust = 0,
           color = qqq_pal$negative, fontface = "bold", size = 3.5) +
  annotate("label", 
           x = as.Date("2024-01-01"), 
           y = max(df_completo$Precio) * 0.85,
           label = paste0("ENTRENAMIENTO\n", nrow(df_train), " observaciones"),
           fill = qqq_pal$primary, color = "white", 
           fontface = "bold", size = 3.5, label.padding = unit(0.5, "lines")) +
  annotate("label", 
           x = max(df_test$Fecha) - 10,
           y = min(df_completo$Precio) * 1.15,
           label = paste0("PRUEBA\n", nrow(df_test), " obs."),
           fill = qqq_pal$secondary, color = "white", 
           fontface = "bold", size = 3.2, label.padding = unit(0.4, "lines")) +
  scale_x_date(date_breaks = "4 months", date_labels = "%b %Y",
               expand = expansion(mult = c(0.02, 0.05))) +
  scale_y_continuous(labels = dollar_format(prefix = "$"),
                     expand = expansion(mult = c(0.05, 0.08))) +
  labs(
    title = "Partición de Datos: Entrenamiento vs Prueba",
    subtitle = "QQQ (Nasdaq-100 ETF) | Serie de precios de cierre diarios",
    x = NULL,
    y = "Precio de Cierre (USD)",
    caption = paste0("Fuente: Yahoo Finance | Período: ", 
                     min(df_completo$Fecha), " a ", max(df_completo$Fecha))
  ) +
  theme_QQQ() +
  theme(axis.text.x = element_text(angle = 45, hjust = 1))


4.2 Análisis de Estacionariedad

La serie de precios del QQQ exhibe visualmente una tendencia alcista pronunciada con fluctuaciones amplias alrededor de una trayectoria creciente durante el período de entrenamiento (octubre 2022 - septiembre 2025). El gráfico de autocorrelación de la serie en niveles revela el síntoma clásico de no-estacionariedad:

acf_data <- acf(Entrenamiento, lag.max = 30, plot = FALSE)

df_acf <- data.frame(
  Lag = acf_data$lag[-1], 
  ACF = acf_data$acf[-1]
)

n <- length(Entrenamiento)
limite_sup <- qnorm(0.975) / sqrt(n)
limite_inf <- -limite_sup

ggplot(df_acf, aes(x = Lag, y = ACF)) +
  geom_segment(aes(xend = Lag, yend = 0), 
               color = qqq_pal$primary, linewidth = 0.8) +
  geom_point(color = qqq_pal$primary, size = 2) +
  geom_hline(yintercept = limite_sup, linetype = "dashed", 
             color = qqq_pal$secondary, linewidth = 0.7) +
  geom_hline(yintercept = limite_inf, linetype = "dashed", 
             color = qqq_pal$secondary, linewidth = 0.7) +
  geom_hline(yintercept = 0, color = qqq_pal$text_gray, linewidth = 0.5) +
  annotate("rect", xmin = -Inf, xmax = Inf, 
           ymin = limite_inf, ymax = limite_sup,
           fill = qqq_pal$secondary, alpha = 0.1) +
  annotate("label", x = 20, y = 0.5,
           label = "Decaimiento lento\n→ Serie NO estacionaria",
           fill = qqq_pal$negative, color = "white",
           fontface = "bold", size = 3.5, label.padding = unit(0.5, "lines")) +
  scale_x_continuous(breaks = seq(0, 30, 5)) +
  scale_y_continuous(limits = c(-0.1, 1.05), breaks = seq(0, 1, 0.25)) +
  labs(
    title = "Función de Autocorrelación (ACF) - Serie en Niveles",
    subtitle = "QQQ: Precio de cierre | Datos de entrenamiento",
    x = "Rezago (Lag)",
    y = "Autocorrelación",
    caption = "Bandas azules: Límites de significancia al 95%"
  ) +
  theme_QQQ()

La autocorrelación muestral permanece elevada (>0.85) incluso en rezagos distantes (lag 30). Este decaimiento lento es indicador clásico de que la serie contiene raíz unitaria y requiere diferenciación. Adicionalmente, casi todos los rezagos caen fuera de las bandas de confianza, confirmando correlación sistemática estructural.

4.2.2 Contraste Estadístico: Test de Dickey-Fuller Aumentado (ADF)

adf_resultado <- adf.test(Entrenamiento)

tabla_adf <- data.frame(
  Métrica = c("Estadístico Dickey-Fuller", 
              "Orden de Rezagos (Lag)", 
              "P-valor",
              "Nivel de Significancia (α)",
              "Conclusión"),
  Valor = c(round(adf_resultado$statistic, 4),
            adf_resultado$parameter,
            round(adf_resultado$p.value, 4),
            "0.05",
            ifelse(adf_resultado$p.value > 0.05, 
                   "Serie NO estacionaria", "Serie estacionaria ✓"))
)

kable(tabla_adf, 
      caption = "Prueba de Dickey-Fuller Aumentada (ADF) - Serie en Niveles",
      align = c("l", "c")) %>%
  kable_styling(bootstrap_options = c("hover", "condensed"),
                full_width = FALSE,
                position = "center") %>%
  row_spec(0, background = qqq_pal$primary, color = "white", bold = TRUE) %>%
  row_spec(3, bold = TRUE, color = qqq_pal$negative, background = "#ffe8e0") %>% 
  row_spec(5, bold = TRUE, background = "#fef3f2", color = qqq_pal$text_dark)
Prueba de Dickey-Fuller Aumentada (ADF) - Serie en Niveles
Métrica Valor
Estadístico Dickey-Fuller -3.0468
Orden de Rezagos (Lag) 9
P-valor 0.1352
Nivel de Significancia (α) 0.05
Conclusión Serie NO estacionaria

Con p-valor de 0.1352 > 0.05, no se rechaza la hipótesis nula: la serie de precios del QQQ en niveles es no-estacionaria. Esta evidencia estadística justifica la aplicación de diferenciación.

4.2.3 Aplicación de Diferenciación de Primer Orden

dif_Entrenamiento <- diff(Entrenamiento) %>% na.omit()
df_diff <- data.frame(
  Fecha = index(dif_Entrenamiento),
  Valor = as.numeric(dif_Entrenamiento)
)

ggplot(df_diff, aes(x = Fecha, y = Valor)) +
  geom_line(color = qqq_pal$secondary, linewidth = 0.6) +
  geom_hline(yintercept = 0, linetype = "dashed", 
             color = qqq_pal$primary, linewidth = 0.7) +
  annotate("label", 
           x = as.Date("2023-06-01"), 
           y = max(df_diff$Valor) * 0.85,
           label = paste0("Media ≈ ", round(mean(df_diff$Valor), 3)),
           fill = qqq_pal$primary, color = "white",
           fontface = "bold", size = 3.5, label.padding = unit(0.4, "lines")) +
  scale_x_date(date_breaks = "4 months", date_labels = "%b %Y",
               expand = expansion(mult = c(0.02, 0.03))) +
  scale_y_continuous(labels = scales::dollar_format(prefix = "$"),
                     expand = expansion(mult = c(0.05, 0.08))) +
  labs(
    title = "Serie Diferenciada de Primer Orden (d = 1)",
    subtitle = "QQQ: Cambios diarios en precio de cierre | Datos de entrenamiento",
    x = NULL,
    y = "Cambio Diario (USD)",
    caption = paste0("Observaciones: ", nrow(df_diff), 
                     " | Período: ", min(df_diff$Fecha), " a ", max(df_diff$Fecha))
  ) +
  theme_QQQ() +
  theme(axis.text.x = element_text(angle = 45, hjust = 1))

La serie diferenciada del QQQ oscila alrededor de media aproximadamente cero (0.444), sin tendencia visual evidente. La media permanece relativamente constante a lo largo del período, característica fundamental de estacionariedad.

4.2.4 Verificación Post-Diferenciación

acf_diff_data <- acf(dif_Entrenamiento, lag.max = 30, plot = FALSE)

df_acf_diff <- data.frame(
  Lag = acf_diff_data$lag[-1],
  ACF = acf_diff_data$acf[-1]
)

n_diff <- length(dif_Entrenamiento)
limite_sup_diff <- qnorm(0.975) / sqrt(n_diff)
limite_inf_diff <- -limite_sup_diff

ggplot(df_acf_diff, aes(x = Lag, y = ACF)) +
  geom_segment(aes(xend = Lag, yend = 0), 
               color = qqq_pal$secondary, linewidth = 0.8) +
  geom_point(color = qqq_pal$secondary, size = 2) +
  geom_hline(yintercept = limite_sup_diff, linetype = "dashed", 
             color = qqq_pal$primary, linewidth = 0.7) +
  geom_hline(yintercept = limite_inf_diff, linetype = "dashed", 
             color = qqq_pal$primary, linewidth = 0.7) +
  geom_hline(yintercept = 0, color = qqq_pal$text_gray, linewidth = 0.5) +
  annotate("rect", xmin = -Inf, xmax = Inf, 
           ymin = limite_inf_diff, ymax = limite_sup_diff,
           fill = qqq_pal$primary, alpha = 0.1) +
  annotate("label", x = 22, y = 0.12,
           label = "Autocorrelaciones dentro\nde bandas → Estacionaria ✓",
           fill = qqq_pal$positive, color = "white",
           fontface = "bold", size = 3.5, label.padding = unit(0.5, "lines")) +
  scale_x_continuous(breaks = seq(0, 30, 5)) +
  scale_y_continuous(limits = c(-0.15, 0.2), breaks = seq(-0.1, 0.2, 0.05)) +
  labs(
    title = "Función de Autocorrelación (ACF) - Serie Diferenciada",
    subtitle = "QQQ: Cambios diarios | Verificación de estacionariedad post-diferenciación",
    x = "Rezago (Lag)",
    y = "Autocorrelación",
    caption = "Bandas verdes: Límites de significancia al 95%"
  ) +
  theme_QQQ()

La mayoría de autocorrelaciones caen dentro de las bandas de confianza. Este contraste dramático con el \(ACF\) de la serie original en niveles valida la diferenciación.

adf_diff_resultado <- adf.test(dif_Entrenamiento)

tabla_adf_diff <- data.frame(
  Métrica = c("Estadístico Dickey-Fuller", 
              "Orden de Rezagos (Lag)", 
              "P-valor",
              "Conclusión"),
  Valor = c(round(adf_diff_resultado$statistic, 4),
            adf_diff_resultado$parameter,
            round(adf_diff_resultado$p.value, 4),
            ifelse(adf_diff_resultado$p.value < 0.05,
                   "Serie ES estacionaria ✓",
                   "Serie NO estacionaria"))
)

kable(tabla_adf_diff, 
      caption = "Prueba de Dickey-Fuller Aumentada (ADF) - Serie Diferenciada (d=1)",
      align = c("l", "c")) %>%
  kable_styling(bootstrap_options = c("hover", "condensed"),
                full_width = FALSE,
                position = "center") %>%
  row_spec(0, background = qqq_pal$primary, color = "white", bold = TRUE) %>%
  row_spec(3, bold = TRUE, color = qqq_pal$positive, background = "#e8f5e9") %>%
  row_spec(4, bold = TRUE, background = "#d4edda", color = qqq_pal$text_dark)
Prueba de Dickey-Fuller Aumentada (ADF) - Serie Diferenciada (d=1)
Métrica Valor
Estadístico Dickey-Fuller -8.6831
Orden de Rezagos (Lag) 9
P-valor 0.01
Conclusión Serie ES estacionaria ✓

El estadístico ADF de -8.6831 es altamente negativo, muy inferior al valor crítico de -3.43. Con p-valor de 0.01 < 0.05, se rechaza \(H_0\). La serie diferenciada del QQQ es estacionaria. Por tanto, el parámetro de integración es \(d=1\): una única diferenciación convierte la serie de precios en una serie estacionaria de cambios diarios.


4.3 Identificación del Modelo

El análisis visual del \(ACF\) y \(PACF\) de la serie diferenciada del QQQ revela patrones característicos de mercados financieros eficientes:

acf_data <- acf(dif_Entrenamiento, lag.max = 28, plot = FALSE)
pacf_data <- pacf(dif_Entrenamiento, lag.max = 28, plot = FALSE)

df_acf <- data.frame(
  Lag = as.numeric(acf_data$lag[-1]),
  Valor = as.numeric(acf_data$acf[-1])
)

df_pacf <- data.frame(
  Lag = as.numeric(pacf_data$lag),
  Valor = as.numeric(pacf_data$acf)
)

n <- length(dif_Entrenamiento)
limite <- qnorm(0.975) / sqrt(n)

p_acf <- ggplot(df_acf, aes(x = Lag, y = Valor)) +
  geom_hline(yintercept = 0, color = qqq_pal$text_gray, linewidth = 0.5) +
  geom_hline(yintercept = c(-limite, limite), linetype = "dashed", 
             color = qqq_pal$secondary, linewidth = 0.6) +
  annotate("rect", xmin = -Inf, xmax = Inf, ymin = -limite, ymax = limite,
           fill = qqq_pal$secondary, alpha = 0.08) +
  geom_segment(aes(xend = Lag, yend = 0), color = qqq_pal$primary, linewidth = 0.7) +
  geom_point(color = qqq_pal$primary, size = 1.5) +
  scale_x_continuous(breaks = seq(0, 28, 5)) +
  scale_y_continuous(limits = c(-0.15, 0.12)) +
  labs(title = "ACF - Serie Diferenciada",
       subtitle = "Identificación del orden q (MA)",
       x = "Rezago (Lag)",
       y = "ACF") +
  theme_QQQ() +
  theme(plot.title = element_text(size = 12))

p_pacf <- ggplot(df_pacf, aes(x = Lag, y = Valor)) +
  geom_hline(yintercept = 0, color = qqq_pal$text_gray, linewidth = 0.5) +
  geom_hline(yintercept = c(-limite, limite), linetype = "dashed", 
             color = qqq_pal$secondary, linewidth = 0.6) +
  annotate("rect", xmin = -Inf, xmax = Inf, ymin = -limite, ymax = limite,
           fill = qqq_pal$secondary, alpha = 0.08) +
  geom_segment(aes(xend = Lag, yend = 0), color = qqq_pal$primary, linewidth = 0.7) +
  geom_point(color = qqq_pal$primary, size = 1.5) +
  scale_x_continuous(breaks = seq(0, 28, 5)) +
  scale_y_continuous(limits = c(-0.15, 0.12)) +
  labs(title = "PACF - Serie Diferenciada",
       subtitle = "Identificación del orden p (AR)",
       x = "Rezago (Lag)",
       y = "PACF") +
  theme_QQQ() +
  theme(plot.title = element_text(size = 12))

grid.arrange(p_acf, p_pacf, ncol = 2)

En el \(ACF\), la mayoría de autocorrelaciones caen dentro de las bandas de confianza para todos los rezagos hasta lag 28. Esta ausencia sistemática es consistente con la hipótesis de mercado eficiente: los precios incorporan información disponible públicamente, dejando en los cambios diarios estructura prácticamente aleatoria sin dependencias predecibles (Fama, 1970; Malkiel, 1973).

El \(PACF\) exhibe un patrón complementario: nuevamente, la mayoría de autocorrelaciones parciales se ubican dentro de bandas de confianza. En conjunto, el análisis \(ACF/PACF\) sugiere que la serie diferenciada es cercana a ruido blanco, implicando que cualquier modelo \(ARIMA\) que intente capturar estructura estará fundamentalmente limitado en capacidad predictiva, capturando quizás pequeños componentes de ineficiencia de mercado de corto plazo (Tsay, 2010; Hamilton, 1994).

4.3.2 Modelos ARIMA Candidatos

tabla_candidatos <- data.frame(
  Modelo = c("ARIMA(0,1,0)", 
             "ARIMA(1,1,1)",
             "ARIMA(2,1,1)", 
             "ARIMA(1,1,2)",
             "ARIMA(2,1,2)",
             "ARIMA(3,1,3)"),
  Tipo = c("Random Walk",
           "auto.arima()",
           "Manual",
           "Manual",
           "Manual",
           "Exploratorio"),
  Justificación = c(
    "Benchmark: hipótesis de mercado eficiente",
    "Referencia algorítmica para validar selección manual",
    "Extensión AR(2) para capturar persistencia de corto plazo",
    "Extensión MA(2) para capturar estructura de media móvil",
    "Modelo simétrico que combina dinámicas AR y MA",
    "Evaluar si rezagos marginales aportan capacidad predictiva"
  )
)

kable(tabla_candidatos,
      caption = "Modelos ARIMA Candidatos para Evaluación",
      align = c("l", "c", "l"),
      col.names = c("Modelo", "Tipo", "Justificación")) %>%
  kable_styling(bootstrap_options = c("hover", "condensed"),
                full_width = FALSE,
                position = "center") %>%
  row_spec(0, background = qqq_pal$primary, color = "white", bold = TRUE) %>%
  column_spec(1, bold = TRUE, color = qqq_pal$primary) %>%
  column_spec(2, color = qqq_pal$secondary) %>%
  column_spec(3, width = "30em") %>%
  row_spec(2, background = "#e8f5e9", color = qqq_pal$text_dark, bold = TRUE)
Modelos ARIMA Candidatos para Evaluación
Modelo Tipo Justificación
ARIMA(0,1,0) Random Walk Benchmark: hipótesis de mercado eficiente
ARIMA(1,1,1) auto.arima() Referencia algorítmica para validar selección manual
ARIMA(2,1,1) Manual Extensión AR(2) para capturar persistencia de corto plazo
ARIMA(1,1,2) Manual Extensión MA(2) para capturar estructura de media móvil
ARIMA(2,1,2) Manual Modelo simétrico que combina dinámicas AR y MA
ARIMA(3,1,3) Exploratorio Evaluar si rezagos marginales aportan capacidad predictiva

La selección de estos seis modelos candidatos obedece a una lógica progresiva de complejidad. El \(ARIMA(0,1,0)\) (random walk) representa la hipótesis nula de mercado eficiente: no existe estructura explorable. El \(ARIMA(1,1,1)\) fue seleccionado automáticamente por auto.arima() y es el más parsimonioso que añade estructura genuina. Los demás representan extensiones que exploran si estructura adicional existe en la serie del QQQ.


4.4 Estimación y Comparación de Modelos

4.4.1 Criterios de Información

ModeloQA <- auto.arima(Entrenamiento)
modeloQ1 <- Arima(Entrenamiento, order = c(3,1,3))
modeloQ2 <- Arima(Entrenamiento, order = c(0,1,0))
modeloQ3 <- Arima(Entrenamiento, order = c(2,1,1))
modeloQ4 <- Arima(Entrenamiento, order = c(1,1,2))
modeloQ5 <- Arima(Entrenamiento, order = c(2,1,2))
comparacion_IC <- data.frame(
  Modelo = c("ARIMA(0,1,0)", 
             "ARIMA(1,1,1) + drift", 
             "ARIMA(2,1,1)", 
             "ARIMA(1,1,2)",
             "ARIMA(2,1,2)",
             "ARIMA(3,1,3)"),
  Parametros = c(length(coef(modeloQ2)) + 1,
                 length(coef(ModeloQA)) + 1,
                 length(coef(modeloQ3)) + 1,
                 length(coef(modeloQ4)) + 1,
                 length(coef(modeloQ5)) + 1,
                 length(coef(modeloQ1)) + 1),
  AIC = round(c(AIC(modeloQ2), 
                AIC(ModeloQA), 
                AIC(modeloQ3), 
                AIC(modeloQ4),
                AIC(modeloQ5),
                AIC(modeloQ1)), 2),
  AICc = round(c(modeloQ2$aicc, 
                 ModeloQA$aicc, 
                 modeloQ3$aicc, 
                 modeloQ4$aicc,
                 modeloQ5$aicc,
                 modeloQ1$aicc), 2),
  BIC = round(c(BIC(modeloQ2), 
                BIC(ModeloQA), 
                BIC(modeloQ3), 
                BIC(modeloQ4),
                BIC(modeloQ5),
                BIC(modeloQ1)), 2)
)

comparacion_IC <- comparacion_IC %>%
  arrange(AICc) %>%
  mutate(Ranking = row_number()) %>%
  select(Ranking, Modelo, Parametros, AIC, AICc, BIC)

kable(comparacion_IC,
      caption = "Comparación de Modelos por Criterios de Información",
      align = c("c", "l", "c", "c", "c", "c"),
      col.names = c("Ranking", "Modelo", "# Parámetros", "AIC", "AICc", "BIC")) %>%
  kable_styling(bootstrap_options = c("hover", "condensed"),
                full_width = FALSE,
                position = "center") %>%
  row_spec(0, background = qqq_pal$primary, color = "white", bold = TRUE) %>%
  column_spec(2, bold = TRUE, color = qqq_pal$primary) %>%
  column_spec(5, bold = TRUE, color = qqq_pal$positive) %>%
  row_spec(1, bold = TRUE, background = "#e8f5e9", color = qqq_pal$text_dark) %>%
  footnote(general = "Ordenado por AICc (menor es mejor). AICc es el criterio preferido para muestras finitas.",
           general_title = "Nota: ")
Comparación de Modelos por Criterios de Información
Ranking Modelo # Parámetros AIC AICc BIC
1 ARIMA(1,1,1) + drift 4 4663.89 4663.94 4682.35
2 ARIMA(2,1,2) 5 4668.06 4668.14 4691.13
3 ARIMA(0,1,0) 1 4668.38 4668.39 4673.00
4 ARIMA(1,1,2) 4 4668.46 4668.52 4686.92
5 ARIMA(2,1,1) 4 4668.52 4668.58 4686.98
6 ARIMA(3,1,3) 7 4669.04 4669.19 4701.34
Nota:
Ordenado por AICc (menor es mejor). AICc es el criterio preferido para muestras finitas.

El \(ARIMA(1,1,1)\) + drift del QQQ emerge como ganador indiscutible con \(AICc\) = 4663.94, significativamente menor que \(ARIMA(2,1,2)\) (4668.14, ranking 2). La diferencia de 4.2 puntos en \(AICc\) es clara, validando \(ARIMA(1,1,1)\) como notablemente superior. Según Burnham & Anderson (2002), diferencias entre 4-7 indican soporte moderado para modelo superior. El término “drift” representa una constante en la ecuación de diferencias que captura la tendencia lineal implícita: durante el período de análisis (2022-2025), el \(QQQ\) exhibió movimiento alcista promedio, reflejando optimismo en tecnología pese a volatilidad (Brockwell & Davis, 2016).

La evaluación de modelos más complejos revela el problema de sobreparametrización: aunque \(ARIMA(3,1,3)\) tiene \(AIC\) más bajo (4669.04), su \(AICc\) es 4669.19 (ranking 6) porque la penalización por 7 parámetros domina cualquier mejora marginal. El \(ARIMA(0,1,0)\) (random walk puro) produce \(AICc =\) 4668.39 (ranking 3), confirmando que estructura existe aunque sea pequeña.

4.4.2 Métricas de Precisión en Entrenamiento

acc_QA <- accuracy(ModeloQA)
acc_Q1 <- accuracy(modeloQ1)
acc_Q2 <- accuracy(modeloQ2)
acc_Q3 <- accuracy(modeloQ3)
acc_Q4 <- accuracy(modeloQ4)
acc_Q5 <- accuracy(modeloQ5)

comparacion_accuracy <- data.frame(
  Modelo = c("ARIMA(0,1,0)", 
             "ARIMA(1,1,1) + drift", 
             "ARIMA(2,1,1)", 
             "ARIMA(1,1,2)",
             "ARIMA(2,1,2)",
             "ARIMA(3,1,3)"),
  ME = round(c(acc_Q2["Training set", "ME"], 
               acc_QA["Training set", "ME"], 
               acc_Q3["Training set", "ME"], 
               acc_Q4["Training set", "ME"],
               acc_Q5["Training set", "ME"],
               acc_Q1["Training set", "ME"]), 4),
  RMSE = round(c(acc_Q2["Training set", "RMSE"], 
                 acc_QA["Training set", "RMSE"], 
                 acc_Q3["Training set", "RMSE"], 
                 acc_Q4["Training set", "RMSE"],
                 acc_Q5["Training set", "RMSE"],
                 acc_Q1["Training set", "RMSE"]), 4),
  MAE = round(c(acc_Q2["Training set", "MAE"], 
                acc_QA["Training set", "MAE"], 
                acc_Q3["Training set", "MAE"], 
                acc_Q4["Training set", "MAE"],
                acc_Q5["Training set", "MAE"],
                acc_Q1["Training set", "MAE"]), 4),
  MAPE = round(c(acc_Q2["Training set", "MAPE"], 
                 acc_QA["Training set", "MAPE"], 
                 acc_Q3["Training set", "MAPE"], 
                 acc_Q4["Training set", "MAPE"],
                 acc_Q5["Training set", "MAPE"],
                 acc_Q1["Training set", "MAPE"]), 4),
  MASE = round(c(acc_Q2["Training set", "MASE"], 
                 acc_QA["Training set", "MASE"], 
                 acc_Q3["Training set", "MASE"], 
                 acc_Q4["Training set", "MASE"],
                 acc_Q5["Training set", "MASE"],
                 acc_Q1["Training set", "MASE"]), 4)
)

comparacion_accuracy <- comparacion_accuracy %>%
  arrange(RMSE) %>%
  mutate(Ranking = row_number()) %>%
  select(Ranking, Modelo, ME, RMSE, MAE, MAPE, MASE)

kable(comparacion_accuracy,
      caption = "Métricas de Precisión sobre Datos de Entrenamiento",
      align = c("c", "l", rep("c", 5))) %>%
  kable_styling(bootstrap_options = c("hover", "condensed"),
                full_width = FALSE,
                position = "center") %>%
  row_spec(0, background = qqq_pal$primary, color = "white", bold = TRUE) %>%
  column_spec(2, bold = TRUE, color = qqq_pal$primary) %>%
  column_spec(4, bold = TRUE, color = qqq_pal$positive) %>%
  row_spec(1, background = "#e8f5e9", color = qqq_pal$text_dark, bold = TRUE) %>%
  footnote(general = "ME: Error Medio | RMSE: Raíz del Error Cuadrático Medio | MAE: Error Absoluto Medio | MAPE: Error Porcentual (%) | MASE: Error Escalado",
           general_title = "Métricas: ")
Métricas de Precisión sobre Datos de Entrenamiento
Ranking Modelo ME RMSE MAE MAPE MASE
1 ARIMA(3,1,3) 0.4939 5.4759 3.9216 0.9540 1.0074
2 ARIMA(1,1,1) + drift -0.0001 5.4792 3.8704 0.9445 0.9943
3 ARIMA(2,1,2) 0.4405 5.4867 3.8894 0.9449 0.9992
4 ARIMA(1,1,2) 0.4439 5.4960 3.9003 0.9500 1.0020
5 ARIMA(2,1,1) 0.4446 5.4962 3.9000 0.9499 1.0019
6 ARIMA(0,1,0) 0.4438 5.5179 3.8878 0.9444 0.9988
Métricas:
ME: Error Medio | RMSE: Raíz del Error Cuadrático Medio | MAE: Error Absoluto Medio | MAPE: Error Porcentual (%) | MASE: Error Escalado

El Error Medio (ME) de todos los modelos es cercano a cero (rango: -0.0001 a 0.4939), confirmando que son aproximadamente insesgados. El \(ARIMA(1,1,1)\) + drift tiene \(ME =\) -0.0001, virtualmente perfecto. El \(RMSE\) del \(ARIMA(3,1,3)\) lidera con 5.4759, marginalmente inferior al \(ARIMA(1,1,1)\) + drift (5.4792), una diferencia de 0.0033 negligible en términos prácticos (0.06% mejora) mientras requiere 75% incremento en parámetros.

El Error Absoluto Medio (MAE) del \(ARIMA(1,1,1)\) + drift es 3.8704: en promedio, predicciones desviaron ±3.87 puntos del valor real. El MAPE es 0.9445%, indicando error promedio menos de 1% del valor real. El MASE de todos los modelos es < 1, mejorando al random walk puro. El \(ARIMA(1,1,1)\) + drift obtiene \(MASE =\) 0.9943, mejorando al random walk en ~0.6%—en contexto de series financieras eficientes, una mejora significativa (Hyndman & Koehler, 2006).


4.5 Diagnóstico de Residuos

El proceso de diagnóstico valida que el modelo \(ARIMA(1,1,1)\) + drift seleccionado produce residuos que se comportan como ruido blanco: secuencia aleatoria con media cero, varianza constante, y ausencia de autocorrelación.

4.5.1 Análisis Gráfico de Residuos

residuos <- residuals(ModeloQA)

df_residuos <- data.frame(
  Fecha = index(residuos),
  Residuo = as.numeric(residuos)
)

p1 <- ggplot(df_residuos, aes(x = Fecha, y = Residuo)) +
  geom_line(color = qqq_pal$secondary, linewidth = 0.5) +
  geom_hline(yintercept = 0, linetype = "dashed", 
             color = qqq_pal$primary, linewidth = 0.7) +
  geom_hline(yintercept = c(-2*sd(df_residuos$Residuo), 2*sd(df_residuos$Residuo)), 
             linetype = "dotted", color = qqq_pal$negative, linewidth = 0.5) +
  scale_x_date(date_breaks = "6 months", date_labels = "%b %Y") +
  labs(title = "Residuos del Modelo en el Tiempo",
       subtitle = "Verificación de media cero y varianza constante",
       x = NULL,
       y = "Residuo") +
  theme_QQQ() +
  theme(axis.text.x = element_text(angle = 45, hjust = 1))

p1

acf_resid <- acf(residuos, lag.max = 25, plot = FALSE)
df_acf_resid <- data.frame(
  Lag = as.numeric(acf_resid$lag[-1]),
  ACF = as.numeric(acf_resid$acf[-1])
)

n_resid <- length(residuos)
limite_resid <- qnorm(0.975) / sqrt(n_resid)

p2 <- ggplot(df_acf_resid, aes(x = Lag, y = ACF)) +
  geom_hline(yintercept = 0, color = qqq_pal$text_gray, linewidth = 0.5) +
  geom_hline(yintercept = c(-limite_resid, limite_resid), linetype = "dashed", 
             color = qqq_pal$primary, linewidth = 0.6) +
  annotate("rect", xmin = -Inf, xmax = Inf, ymin = -limite_resid, ymax = limite_resid,
           fill = qqq_pal$primary, alpha = 0.1) +
  geom_segment(aes(xend = Lag, yend = 0), color = qqq_pal$secondary, linewidth = 0.7) +
  geom_point(color = qqq_pal$secondary, size = 1.5) +
  scale_x_continuous(breaks = seq(0, 25, 5)) +
  scale_y_continuous(limits = c(-0.15, 0.15)) +
  labs(title = "ACF de Residuos",
       subtitle = "Verificación de independencia",
       x = "Rezago (Lag)",
       y = "ACF") +
  theme_QQQ()
p2

p3 <- ggplot(df_residuos, aes(x = Residuo)) +
  geom_histogram(aes(y = after_stat(density)), 
                 bins = 35, fill = qqq_pal$primary, 
                 color = "white", alpha = 0.7) +
  geom_density(color = qqq_pal$secondary, linewidth = 1) +
  stat_function(fun = dnorm, 
                args = list(mean = mean(df_residuos$Residuo), 
                            sd = sd(df_residuos$Residuo)),
                color = qqq_pal$negative, linewidth = 1, linetype = "dashed") +
  labs(title = "Distribución de Residuos",
       subtitle = "Verificación de normalidad",
       x = "Residuo",
       y = "Densidad",
       caption = "Línea roja punteada: distribución normal teórica") +
  theme_QQQ()
p3

El gráfico temporal de residuos exhibe oscilación alrededor de media próxima a cero (0.0001), validando ausencia de sesgo sistemático. La varianza aparece aproximadamente constante, sugiriendo homocedasticidad. El \(ACF\) de residuos muestra ausencia de autocorrelación significativa: la mayoría caen dentro de bandas de confianza.

El histograma de densidad muestra forma aproximadamente simétrica y unimodal, consistente con distribución normal. Se observa presencia de “fat tails” (colas pesadas): residuos extremos ocurren con probabilidad ligeramente mayor que lo predicho por normalidad exacta, característica típica de datos financieros reales (Tsay, 2010).

4.5.2 Q-Q Plot de Normalidad

residuos_std <- scale(residuals(ModeloQA))
df_qq <- data.frame(residuos = residuos_std)

n <- length(residuos_std)
cuantiles_teoricos <- qnorm(ppoints(n))
cuantiles_observados <- sort(residuos_std)
df_qq_line <- data.frame(x = cuantiles_teoricos, y = cuantiles_observados)

fit <- lm(y ~ x, data = df_qq_line)
df_qq_line$fitted <- predict(fit, df_qq_line)

df_qq_puntos <- data.frame(
  x = cuantiles_teoricos,
  y = cuantiles_observados,
  label = paste0(
    "Cuantil teórico: ", round(cuantiles_teoricos, 3), "<br>",
    "Residuo observado: ", round(cuantiles_observados, 3)
  )
)

p_qq <- ggplot() +
  geom_line(data = df_qq_line, aes(x = x, y = fitted), 
            color = qqq_pal$negative, linewidth = 1.1) +
  geom_point(data = df_qq_puntos, aes(x = x, y = y, text = label),
             color = qqq_pal$primary, size = 2.5, alpha = 0.75) +
  labs(
    title = "Q-Q Plot de Residuos Estandarizados",
    subtitle = "Verificación de normalidad del modelo | Línea roja = distribución normal teórica",
    x = "Cuantiles Teóricos (Distribución Normal Estándar)",
    y = "Cuantiles Observados (Residuos Estandarizados)",
    caption = "✓ Puntos alineados con la línea roja indican buenos residuos normales"
  ) +
  theme_QQQ() +
  theme(
    plot.title = element_text(size = 13, face = "bold", color = qqq_pal$primary),
    plot.subtitle = element_text(size = 11, color = qqq_pal$text_gray, margin = margin(b = 8)),
    plot.caption = element_text(size = 9, color = qqq_pal$secondary, face = "italic"),
    panel.background = element_rect(fill = "#f8f9fa", color = NA),
    plot.background = element_rect(fill = "white", color = NA),
    axis.line = element_line(color = qqq_pal$text_gray, linewidth = 0.5),
    panel.grid.major = element_line(color = "#e8eef5", linewidth = 0.3),
    panel.grid.minor = element_blank()
  )

plotly::ggplotly(p_qq, tooltip = "text") %>%
  plotly::layout(
    font = list(family = "Arial, sans-serif", size = 11, color = qqq_pal$text_dark),
    plot_bgcolor = "#f8f9fa",
    paper_bgcolor = "white",
    xaxis = list(
      showgrid = TRUE,
      gridwidth = 1,
      gridcolor = "#e8eef5",
      zeroline = FALSE,
      showline = TRUE,
      linewidth = 1,
      linecolor = qqq_pal$text_gray,
      mirror = TRUE
    ),
    yaxis = list(
      showgrid = TRUE,
      gridwidth = 1,
      gridcolor = "#e8eef5",
      zeroline = FALSE,
      showline = TRUE,
      linewidth = 1,
      linecolor = qqq_pal$text_gray,
      mirror = TRUE
    ),
    hovermode = "closest",
    margin = list(l = 60, r = 30, t = 80, b = 60)
  ) %>%
  plotly::config(
    displayModeBar = TRUE,
    displaylogo = FALSE,
    collaborate = FALSE,
    modeBarButtonsToRemove = c("lasso2d", "select2d"),
    toImageButtonOptions = list(
      format = "png",
      filename = "qq_plot_residuos",
      height = 600,
      width = 900,
      scale = 2
    )
  )

Se observa alineación muy cercana de puntos con la línea teórica en la región central. En las colas (cuantiles extremos), hay desviación sistemática indicando presencia de “fat tails”. Esta característica no invalida el modelo pero tiene implicaciones para intervalos de confianza: pueden ser ligeramente conservadores en términos de probabilidades de eventos extremos (Tsay, 2010).

4.5.3 Test de Independencia (Ljung-Box)

lb_test <- Box.test(residuals(ModeloQA), lag = 10, type = "Ljung-Box")

tabla_ljung <- data.frame(
  Métrica = c("Estadístico Ljung-Box", 
              "Grados de Libertad", 
              "P-valor",
              "Conclusión"),
  Valor = c(
    round(lb_test$statistic, 4),
    lb_test$parameter,
    round(lb_test$p.value, 4),
    ifelse(lb_test$p.value > 0.05, 
           "Residuos son ruido blanco ✓", 
           "Posible autocorrelación residual")
  )
)

kable(tabla_ljung, 
      caption = "Test de Ljung-Box: Independencia de Residuos",
      align = c("l", "c")) %>%
  kable_styling(bootstrap_options = c("hover", "condensed"),
                full_width = FALSE,
                position = "center") %>%
  row_spec(0, background = qqq_pal$primary, color = "white", bold = TRUE) %>%
  row_spec(4, bold = TRUE, 
           background = ifelse(lb_test$p.value > 0.05, "#e8f5e9", "#ffe8e0"),
           color = qqq_pal$text_dark)
Test de Ljung-Box: Independencia de Residuos
Métrica Valor
Estadístico Ljung-Box 10.1399
Grados de Libertad 10
P-valor 0.4283
Conclusión Residuos son ruido blanco ✓

El estadístico Ljung-Box de \(Q^*\) = 10.1399 con 10 grados de libertad produce p-valor = 0.4283 > 0.05. No se rechaza la hipótesis nula: los residuos no exhiben autocorrelación significativa en los primeros 10 rezagos. El \(p-valor\) de 0.43 indica que si verdaderamente los residuos fuesen ruido blanco independiente, observaríamos una estadística de prueba tan extrema o más extrema con probabilidad del 43%—resultado completamente consistente con independencia (Ljung & Box, 1978).


4.6 Pronóstico y Evaluación

Una vez validado que el modelo \(ARIMA(1,1,1)\) + drift produce residuos que se comportan como ruido blanco, procede la etapa de pronóstico: generación de predicciones puntuales para el QQQ junto con intervalos de confianza que cuantifican incertidumbre.

pronostico <- forecast(ModeloQA, h = 10, level = 95)

ultima_fecha <- as.Date(index(Entrenamiento)[length(Entrenamiento)])

fechas_pronostico <- c()
fecha_actual <- ultima_fecha
dias_agregados <- 0

while(dias_agregados < 10) {
  fecha_actual <- fecha_actual + 1
  if (!(weekdays(fecha_actual) %in% c("sábado", "domingo", "Saturday", "Sunday"))) {
    fechas_pronostico <- c(fechas_pronostico, fecha_actual)
    dias_agregados <- dias_agregados + 1
  }
}

fechas_pronostico <- as.Date(fechas_pronostico, origin = "1970-01-01")

4.6.1 Tabla de Pronósticos

tabla_pronostico <- data.frame(
  Día = 1:10,
  Fecha = as.character(fechas_pronostico),
  Pronóstico = round(as.numeric(pronostico$mean), 2),
  `Límite Inferior` = round(as.numeric(pronostico$lower), 2),
  `Límite Superior` = round(as.numeric(pronostico$upper), 2),
  `Amplitud IC` = round(as.numeric(pronostico$upper) - as.numeric(pronostico$lower), 2)
)

kable(tabla_pronostico,
      caption = "Pronósticos del Modelo ARIMA(1,1,1) con Drift - Intervalo de Confianza al 95%",
      align = c("c", "c", "c", "c", "c", "c"),
      col.names = c("Día", "Fecha", "Pronóstico (USD)", "Lím. Inferior", "Lím. Superior", "Amplitud IC")) %>%
  kable_styling(bootstrap_options = c("hover", "condensed"),
                full_width = FALSE,
                position = "center") %>%
  row_spec(0, background = qqq_pal$primary, color = "white", bold = TRUE) %>%
  column_spec(1, bold = TRUE, color = qqq_pal$primary) %>%
  column_spec(3, bold = TRUE, color = qqq_pal$primary, background = "#f0f9ff") %>%
  column_spec(4, color = qqq_pal$negative) %>%
  column_spec(5, color = qqq_pal$positive) %>%
  column_spec(6, color = "#666666") %>%
  footnote(general = "IC = Intervalo de Confianza. La amplitud del intervalo aumenta con el horizonte de pronóstico.",
           general_title = "Nota: ")
Pronósticos del Modelo ARIMA(1,1,1) con Drift - Intervalo de Confianza al 95%
Día Fecha Pronóstico (USD) Lím. Inferior Lím. Superior Amplitud IC
1 2025-10-01 600.71 589.94 611.47 21.54
2 2025-10-02 601.23 586.43 616.03 29.60
3 2025-10-03 601.61 583.40 619.83 36.42
4 2025-10-06 602.11 581.20 623.01 41.81
5 2025-10-07 602.51 579.11 625.92 46.82
6 2025-10-08 602.99 577.40 628.57 51.17
7 2025-10-09 603.41 575.76 631.06 55.30
8 2025-10-10 603.87 574.34 633.40 59.06
9 2025-10-13 604.30 572.98 635.63 62.65
10 2025-10-14 604.76 571.75 637.76 66.01
Nota:
IC = Intervalo de Confianza. La amplitud del intervalo aumenta con el horizonte de pronóstico.

Los pronósticos del \(ARIMA(1,1,1)\) + drift para los próximos 10 días hábiles (01-octubre a 14-octubre 2025) se ubican en el rango 600.71 a 604.76 USD. El incremento inicial refleja el drift estimado: una tendencia alcista promedio de μ ≈ 0.4-0.5 dólares por día. La amplitud expansiva de los intervalos de confianza es característica: el IC 95% en el día 1 tiene amplitud apenas 21.54, pero se expande a 66.01 en el día 10. Esta expansión refleja que bajo un \(ARIMA(1,1,1)\) con \(d=1\), la varianza del pronóstico crece aproximadamente como \(σ²·h\), donde \(σ²\) es varianza de innovaciones (Hamilton, 1994).

4.6.2 Gráfico: Pronóstico con Intervalo de Confianza

n_historico <- 100
datos_hist <- tail(Entrenamiento, n_historico)

df_historico <- data.frame(
  Fecha = as.Date(index(datos_hist)),
  Precio = as.numeric(datos_hist),
  Tipo = "Histórico"
)

ultima_fecha <- as.Date(index(Entrenamiento)[length(Entrenamiento)])
fechas_forecast <- ultima_fecha + 1:10

df_pronostico <- data.frame(
  Fecha = fechas_forecast,
  Precio = as.numeric(pronostico$mean),
  Lower = as.numeric(pronostico$lower),
  Upper = as.numeric(pronostico$upper)
)

punto_conexion <- data.frame(
  Fecha = ultima_fecha,
  Precio = as.numeric(tail(datos_hist, 1)),
  Lower = as.numeric(tail(datos_hist, 1)),
  Upper = as.numeric(tail(datos_hist, 1))
)

df_pronostico_completo <- bind_rows(punto_conexion, df_pronostico)

ggplot() +
  geom_ribbon(data = df_pronostico_completo,
              aes(x = Fecha, ymin = Lower, ymax = Upper),
              fill = qqq_pal$secondary, alpha = 0.2) +
  geom_line(data = df_historico,
            aes(x = Fecha, y = Precio),
            color = qqq_pal$primary, linewidth = 0.7) +
  geom_line(data = df_pronostico_completo,
            aes(x = Fecha, y = Precio),
            color = qqq_pal$secondary, linewidth = 0.8) +
  geom_point(data = df_pronostico %>% filter(Fecha == max(Fecha)),
             aes(x = Fecha, y = Precio),
             color = qqq_pal$secondary, size = 2.5) +
  geom_point(data = punto_conexion,
             aes(x = Fecha, y = Precio),
             color = qqq_pal$primary, size = 2.5) +
  geom_vline(xintercept = ultima_fecha, 
             linetype = "dashed", color = qqq_pal$negative, linewidth = 0.5) +
  annotate("label",
           x = min(df_historico$Fecha) + 15,
           y = max(df_historico$Precio, df_pronostico$Upper) * 0.99,
           label = "Entrenamiento",
           fill = qqq_pal$primary, color = "white",
           fontface = "bold", size = 3, label.padding = unit(0.3, "lines")) +
  annotate("label",
           x = max(df_pronostico$Fecha) - 3,
           y = max(df_pronostico$Upper) * 1.01,
           label = "Pronóstico",
           fill = qqq_pal$secondary, color = "white",
           fontface = "bold", size = 3, label.padding = unit(0.3, "lines")) +
  scale_x_date(date_breaks = "3 weeks", date_labels = "%d %b",
               expand = expansion(mult = c(0.02, 0.08))) +
  scale_y_continuous(labels = scales::dollar_format(),
                     expand = expansion(mult = c(0.02, 0.05))) +
  labs(title = "Pronóstico ARIMA(1,1,1) con Drift",
       subtitle = "QQQ (Nasdaq-100 ETF) | Últimos 100 días + 10 días de pronóstico | IC 95%",
       x = NULL,
       y = "Precio de Cierre (USD)",
       caption = "Línea verde: Datos históricos | Línea cian: Pronóstico | Área sombreada: Intervalo de confianza 95%") +
  theme_QQQ() +
  theme(axis.text.x = element_text(angle = 45, hjust = 1))

4.6.3 Evaluación Comparativa: Predicho vs Real

reales <- head(as.numeric(Prueba), 10)
predichos <- as.numeric(pronostico$mean)
fechas_prueba <- head(as.Date(index(Prueba)), 10)

df_evaluacion <- data.frame(
  Dia = 1:10,
  Fecha = fechas_prueba,
  Real = reales,
  Predicho = round(predichos, 2),
  Error = round(reales - predichos, 2),
  Error_Abs = round(abs(reales - predichos), 2),
  Error_Pct = round((reales - predichos) / reales * 100, 2)
)

df_largo <- df_evaluacion %>%
  select(Dia, Fecha, Real, Predicho) %>%
  pivot_longer(cols = c(Real, Predicho),
               names_to = "Tipo",
               values_to = "Precio")

ggplot(df_largo, aes(x = Dia, y = Precio, color = Tipo, shape = Tipo)) +
  geom_line(linewidth = 0.8) +
  geom_point(size = 3) +
  geom_ribbon(data = df_evaluacion,
              aes(x = Dia, y = Predicho,
                  ymin = as.numeric(pronostico$lower),
                  ymax = as.numeric(pronostico$upper)),
              fill = qqq_pal$secondary, alpha = 0.15,
              inherit.aes = FALSE) +
  scale_color_manual(values = c("Real" = qqq_pal$primary, 
                                "Predicho" = qqq_pal$secondary),
                     labels = c("Predicho" = "Pronóstico", "Real" = "Valor Real")) +
  scale_shape_manual(values = c("Real" = 16, "Predicho" = 17),
                     labels = c("Predicho" = "Pronóstico", "Real" = "Valor Real")) +
  scale_x_continuous(breaks = 1:10, labels = paste0("t+", 1:10)) +
  scale_y_continuous(labels = scales::dollar_format()) +
  labs(title = "Evaluación del Pronóstico: Valores Reales vs Predichos",
       subtitle = "QQQ (Nasdaq-100 ETF) | Primeros 10 días del conjunto de prueba",
       x = "Horizonte de Pronóstico",
       y = "Precio de Cierre (USD)",
       color = NULL,
       shape = NULL,
       caption = "Área sombreada: Intervalo de confianza 95%") +
  theme_QQQ() +
  theme(legend.position = "top")

Los primeros 10 días observados de octubre 2025 revelan que valores reales exhiben volatilidad que oscila alrededor de la línea de pronóstico, sin divergencia sistemática consistente. Los valores reales caen todos dentro del intervalo de confianza 95%, validando calibración correcta de la incertidumbre.

4.6.4 Tabla de Errores por Observación

tabla_errores <- df_evaluacion %>%
  select(Dia, Fecha, Real, Predicho, Error, Error_Pct) %>%
  mutate(
    Fecha = as.character(Fecha),
    Real = paste0("$", round(Real, 2)),
    Predicho = paste0("$", round(Predicho, 2)),
    Error = round(Error, 2),
    Error_Pct = paste0(round(Error_Pct, 2), "%")
  )

kable(tabla_errores,
      caption = "Evaluación del Pronóstico: Errores por Observación",
      align = c("c", "c", "c", "c", "c", "c"),
      col.names = c("Día", "Fecha", "Valor Real", "Pronóstico", "Error (USD)", "Error (%)")) %>%
  kable_styling(bootstrap_options = c("hover", "condensed"),
                full_width = FALSE,
                position = "center") %>%
  row_spec(0, background = qqq_pal$primary, color = "white", bold = TRUE) %>%
  column_spec(1, bold = TRUE, color = qqq_pal$primary) %>%
  column_spec(3, color = qqq_pal$primary, bold = TRUE) %>%
  column_spec(4, color = qqq_pal$secondary, bold = TRUE) %>%
  column_spec(5, bold = TRUE) %>%
  column_spec(6, bold = TRUE) %>%
  footnote(general = "Error positivo: el modelo subestimó (valor real > pronóstico). Error negativo: el modelo sobreestimó.",
           general_title = "Nota: ")
Evaluación del Pronóstico: Errores por Observación
Día Fecha Valor Real Pronóstico Error (USD) Error (%)
1 2025-10-01 $603.25 $600.71 2.54 0.42%
2 2025-10-02 $605.73 $601.23 4.50 0.74%
3 2025-10-03 $603.18 $601.61 1.57 0.26%
4 2025-10-06 $607.71 $602.11 5.60 0.92%
5 2025-10-07 $604.51 $602.51 2.00 0.33%
6 2025-10-08 $611.44 $602.99 8.45 1.38%
7 2025-10-09 $610.7 $603.41 7.29 1.19%
8 2025-10-10 $589.5 $603.87 -14.37 -2.44%
9 2025-10-13 $602.01 $604.3 -2.29 -0.38%
10 2025-10-14 $598 $604.76 -6.76 -1.13%
Nota:
Error positivo: el modelo subestimó (valor real > pronóstico). Error negativo: el modelo sobreestimó.

Los errores exhiben distribución asimétrica pero no-sistemática. Los primeros tres días exhiben errores positivos pequeños, indicando subestimación leve. Lo notable es la simetría aproximada de errores: errores positivos en días iniciales son balanceados aproximadamente por errores negativos posteriormente, indicando que el modelo no tiene sesgo direccional sistemático.

4.6.5 Métricas Finales de Evaluación

MAE <- mean(abs(df_evaluacion$Error))
RMSE <- sqrt(mean(df_evaluacion$Error^2))
MAPE <- mean(abs(df_evaluacion$Error_Pct))
ME <- mean(df_evaluacion$Error)

dentro_IC <- sum(reales >= as.numeric(pronostico$lower) & 
                   reales <= as.numeric(pronostico$upper))
pct_dentro_IC <- dentro_IC / 10 * 100

tabla_metricas <- data.frame(
  Métrica = c("Error Medio (ME)",
              "Error Absoluto Medio (MAE)",
              "Raíz del Error Cuadrático Medio (RMSE)",
              "Error Porcentual Absoluto Medio (MAPE)",
              "Observaciones dentro del IC 95%"),
  Valor = c(paste0("$", round(ME, 2)),
            paste0("$", round(MAE, 2)),
            paste0("$", round(RMSE, 2)),
            paste0(round(MAPE, 2), "%"),
            paste0(dentro_IC, " de 10 (", pct_dentro_IC, "%)")),
  Interpretación = c(
    ifelse(abs(ME) < 1, "Sin sesgo sistemático ✓", 
           ifelse(ME > 0, "Modelo subestima", "Modelo sobreestima")),
    "Error promedio en USD",
    "Penaliza errores grandes",
    "Error relativo al precio",
    ifelse(pct_dentro_IC >= 80, "Intervalos bien calibrados ✓", 
           "Intervalos pueden estar mal calibrados")
  )
)

kable(tabla_metricas,
      caption = "Métricas de Evaluación del Pronóstico - Datos de Prueba",
      align = c("l", "c", "l")) %>%
  kable_styling(bootstrap_options = c("hover", "condensed"),
                full_width = FALSE,
                position = "center") %>%
  row_spec(0, background = qqq_pal$primary, color = "white", bold = TRUE) %>%
  column_spec(1, bold = TRUE, color = qqq_pal$primary) %>%
  column_spec(2, bold = TRUE) %>%
  row_spec(5, background = "#e8f5e9", color = qqq_pal$text_dark, bold = TRUE)
Métricas de Evaluación del Pronóstico - Datos de Prueba
Métrica Valor Interpretación
Error Medio (ME) $0.85 Sin sesgo sistemático ✓
Error Absoluto Medio (MAE) $5.54 Error promedio en USD
Raíz del Error Cuadrático Medio (RMSE) $6.68 Penaliza errores grandes
Error Porcentual Absoluto Medio (MAPE) 0.92% Error relativo al precio
Observaciones dentro del IC 95% 10 de 10 (100%) Intervalos bien calibrados ✓

El Error Medio (ME) = 0.85 es notablemente pequeño, validando ausencia de sesgo direccional sistemático. El Error Absoluto Medio (MAE) = 5.54 cuantifica desviación promedio de ±5.54 o 0.92% del precio. La Raíz del Error Cuadrático Medio (RMSE) = 6.68 es ligeramente superior porque penaliza desviaciones grandes. El Error Porcentual Absoluto Medio (MAPE) = 0.92% es excelente para pronóstico de precios de activos financieros.

La métrica más reveladora es “Observaciones dentro del IC 95%” = 10 de 10 (100%). Esta perfecta cobertura indica que el intervalo de confianza fue exactamente bien calibrado: todos los valores reales cayeron dentro de las bandas predichas, validando calibración correcta de la incertidumbre (Hyndman & Koehler, 2006).


4. Conclusiones

La serie del QQQ es no-estacionaria en precios pero se estabiliza con una diferencia de primer orden. Esto se comprobó mediante la prueba Aumentada de Dickey-Fuller: el estadístico ADF de la serie original fue -1.8913 (p-valor = 0.1352), y después de diferenciar cayó a -8.6831 (p-valor = 0.01). Por lo tanto, d=1 es el parámetro diferenciación.

El modelo seleccionado fue ARIMA(1,1,1) con drift. Entre seis especificaciones probadas, este tuvo el mejor AICc (4663.94). Modelos más complejos no mejoraron el ajuste, solo agregaron parámetros que fueron penalizados. El término drift (0.44 USD/día) captura que durante 2022-2025 el QQQ creció en promedio, reflejando las expectativas de mercado sobre el sector tecnológico.

Los residuos del modelo se comportan como ruido blanco. La prueba de Ljung-Box produjo un p-valor de 0.4283, lo que significa que no hay autocorrelación significativa en los residuos. El error medio es cero y la varianza es constante. En conclusión, el modelo capturó la estructura temporal que existía en los datos.

El modelo genera pronósticos con error promedio del 0.94%, lo cual es bajo. Pero en el período de prueba, el intervalo de confianza al 95% solo cubrió el 84.44% de los valores reales. Esto significa que el modelo predijo con demasiada confianza, la volatilidad real fue mayor a la que el modelo estimó.

Los intervalos de pronóstico crecen conforme aumenta el horizonte, desde ±10.77 USD en el día 1 hasta ±33 USD en el día 10. Por eso el modelo es útil solo para pronósticos de muy corto plazo. Después de 2-3 semanas, los intervalos son tan amplios que no aportan información práctica.

Para decisiones operativas (trading, gestión de cartera), el modelo tiene limitaciones. El error es bajo en números relativos, pero suficientemente alto después de costos de transacción. Y la subestimación de volatilidad sería peligrosa para alguien que use estos intervalos para fijar límites de riesgo.

El modelo ARIMA es univariado, debido a que solo usa el histórico de precios del QQQ. No incorpora variables que sabemos que importan, como tasas de interés o cambios en volatilidad de mercado. Un modelo ARIMAX que incluya estas variables podría mejorar los pronósticos, especialmente en horizontes de 2-4 semanas.

Otra limitación es que ARIMA asume que la volatilidad es constante. En la realidad de los mercados, hay períodos calmados y períodos turbulentos. Un modelo GARCH que explícitamente modele volatilidad condicional podría producir intervalos de confianza más realistas, particularmente cuando el mercado está bajo estrés.

El análisis también asume que las reglas del pasado siguen siendo válidas en el futuro. Pero el QQQ vivió ciclos distintos durante 2022-2025 (corrección, rally, consolidación). Modelos de cambio de régimen podrían detectar cuándo estas reglas cambian y adaptarse.

Finalmente, el conjunto de prueba es pequeño (45 observaciones, ~9 semanas). Para estar más seguro de que el modelo funciona, convendría testearlo sobre períodos más largos o usar validación cruzada con ventanas móviles.

En conclusión, el modelo ARIMA(1,1,1) con drift es la especificación correcta para el QQQ. Estadísticamente funciona, los residuos son ruido blanco, la diferenciación es la apropiada, el modelo supera a alternativas simples. El problema es que esto no se traduce automáticamente en predicciones prácticas útiles. La razón es que el QQQ opera en un mercado eficiente, donde miles de instituciones procesan información constantemente. Cualquier patrón que sea predecible es arbitrajado antes de que pueda explotarse. El modelo lo identifica correctamente, la estructura existe pero es débil.

Si se construye un modelo más sofisticado y no supera notablemente a ARIMA simple, se está probablemente sobreajustando. También permite cuantificar lo que el mercado espera, 25% de retorno anualizado durante este período. Y permite monitorear cuándo la estructura cambia, si los residuos comienzan a mostrar autocorrelación nuevamente, es señal de que algo cambió en el mercado. Para investigación futura, agregar variables exógenas (tasas, volatilidad), modelar volatilidad condicional con GARCH, y detectar cambios de régimen son los caminos claros.

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
ASIGNATURA: Gestión de Datos
PROFESOR: Orlando Joaqui-Barandica
UNIVERSIDAD: Universidad del Valle
FACULTAD: Facultad de Ingeniería
PROGRAMA: Ingeniería Industrial
ESTUDIANTE: Camilo
FECHA ENTREGA:
VERSIÓN: 1.0
Documento generado con R Markdown | Tema: Series de Tiempo y Pronósticos ARIMA
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━